/* REXX exec/edit macro to convert REXX to 'HILITE'd HTML             */
/*** trace ?r ***************************************************** \| *
*               (C) Copyright Robert AH Prins, 2007-2016               *
*                       (C) Stefan B, 2007-2007                        *
************************************************************************
*  ------------------------------------------------------------------  *
* | Date       | By   | Remarks                                      | *
* |------------+------+----------------------------------------------| *
* |            |      |                                              | *
* |------------+------+----------------------------------------------| *
* | 2016-11-24 | RAHP | Add "ehixmit" interface                      | *
* |------------+------+----------------------------------------------| *
* | 2016-11-18 | RAHP | Multiple updates/simplifications             | *
* |------------+------+----------------------------------------------| *
* | 2012-06-25 | RAHP | Add IP address                               | *
* |------------+------+----------------------------------------------| *
* | 2012-06-08 | RAHP | Add ¢ HTML entity                       | *
* |------------+------+----------------------------------------------| *
* | 2009-07-27 | RAHP | Use pop-up on ISPF to display progress       | *
* |------------+------+----------------------------------------------| *
* | 2009-07-02 | RAHP | Add selection for short CSS 'em' colors      | *
* |------------+------+----------------------------------------------| *
* | 2009-04-22 | RAHP | Update comment                               | *
* |------------+------+----------------------------------------------| *
* | 2009-04-16 | RAHP | Main parsing loop needs to end on exactly    | *
* |            |      | '==' equal, as '0d0a'x equals '' on Regina   | *
* |------------+------+----------------------------------------------| *
* | 2009-04-01 | RAHP | Add font selection for generated HTML        | *
* |------------+------+----------------------------------------------| *
* | 2009-02-09 | RAHP | RACF problem with 'html' extension @ NVSM    | *
* |------------+------+----------------------------------------------| *
* | 2007-09-24 | RAHP | Further tweaks                               | *
* |------------+------+----------------------------------------------| *
* | 2007-09-18 | RAHP | - add GPL V3 License                         | *
* |            |      | - use EHISUPP 'get_options' to retrieve some | *
* |            |      |   processing options                         | *
* |------------+------+----------------------------------------------| *
* | 2007-09-06 | RAHP | Cater for PC environment                     | *
* |------------+------+----------------------------------------------| *
* | 2007-08-30 | RAHP | Further fine-tuning (HTLM 4.01 Strict)       | *
* |------------+------+----------------------------------------------| *
* | 2007-08-23 | RAHP | Factor out common 'EHIxxxx' routines         | *
* |------------+------+----------------------------------------------| *
* | 2007-08-20 | RAHP | - remove more bugs (rc/sigl/source)          | *
* |            |      | - add (nested) parentheses hilighting        | *
* |------------+------+----------------------------------------------| *
* | 2007-08-16 | RAHP | Reformat to Prins' standards, remove nested  | *
* |            |      | comment bug                                  | *
* |------------+------+----------------------------------------------| *
* | 2007-08-08 | SB   | Initial version                              | *
* |------------+------+----------------------------------------------| *
************************************************************************
* EHIREXX is a REXX exec/edit macro that analyses REXX code and builds *
* a HTML file with the color attributes as used by ISPF Edit.          *
*                                                                      *
* This file can be transferred to the PC by using ISPF Workstation     *
* Agent. In addition the exec might invoke the Windows application     *
* associated with file extension ".html"                               *
*                                                                      *
* The exec runs as ISPF edit macro or might be used as line command    *
* on the extended member list of ISPF List Utility (usually menu       *
* option 3.4).                                                         *
*                                                                      *
* In addition the exec can be invoked on the command line. In this     *
* case the dataset name has to be supplied as invocation parameter.    *
*                                                                      *
* Original author: Stefan B. (See <http://www.schlabb.de>), based on   *
*                  an idea of W. Schäfer, rubin Software, see          *
*                  <http://www.rubin-software.de/index.php>            *
*                                                                      *
* See <http://mvshelp.net/vbforums/showthread.php?t=24126> for the     *
* original question on how to parse nested comments in REXX. The parse *
* code is an adaptation of Mark Baxter's reply.                        *
*                                                                      *
* t_rex will contain the environment. It can be:                       *
*                                                                      *
* - TSO     - TSO/ISPF                                                 *
* - MVS     - z/OS (PGM=IRXJCL)                                        *
* - SYSTEM  - Regina                                                   *
* - COMMAND - PC DOS 7/2000                                            *
* - CMD     - Object REXX (OS/2, Windoze)                              *
************************************************************************
* Send questions, suggestions and/or bug reports to:                   *
*                                                                      *
* robert@prino.org / robert.ah.prins@gmail.com                         *
*                                                                      *
* Robert AH Prins                                                      *
* Taboralaan 46                                                        *
* 8400 Oostende                                                        *
* Belgium                                                              *
************************************************************************
* This program 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 3 of       *
* the License, or (at your option) any later version.                  *
*                                                                      *
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>  *
***********************************************************************/
parse source source
parse value source with . . moi . . . cmdenv aspace .

t_rex = address()

if t_rex  = 'TSO' &,
   aspace = 'ISPF' then
  do
    "ispexec vget (zenvir)"
    envir = strip(substr(zenvir, 17, 8))
  end
else
  envir = 'OTHER'

parse arg idsn

call get_source                /* Read the REXX program source        */
call init_vars                 /* Initialize the global variables     */
call build_html                /* Now go on and build the HTML output */

call ehisupp 'generate_output,'sep','htmlout  || sep ||,
                                     odsn     || sep ||,
                                     title    || sep ||,
                                     header   || sep ||,
                                     footer   || sep ||,
                                     htmlfont

"ispexec vget (ehixmit) shared"

if rc = 0 then
  do
    "ispexec verase (rexxparm) shared"
    "isredit can"
    exit
  end

if t_rex  = 'TSO' &,
   aspace = 'ISPF' then
  if envir \= 'BATCH' then
    do
      /*****************************************************************
      * Show the resulting dataset, if desired                         *
      *****************************************************************/
      if view_html = 'YES' then
        "ispexec view dataset("odsn")"

      /*****************************************************************
      * Transfer the html file to the PC                               *
      *****************************************************************/
      if xfer_wsa = 'YES' then
        call ehisupp 'xfer_and_show_html,'sep','dir_pc   || sep ||,
                                                htmlfile || sep ||,
                                                odsn     || sep ||,
                                                ipaddr   || sep ||,
                                                start_browser
    end
  else
    do
      if macmode then
        "isredit end"
    end
exit

/***********************************************************************
* TRANSLATE_ENTITIES                                                   *
*                                                                      *
* This procedure translates special characters to HTML entities        *
***********************************************************************/
translate_entities: procedure expose special_chars special_html
  parse arg in

  out = ''

  if translate(in, ' ', special_chars) = in then
    out = in
  else
    do while in \== ''
      c = left(in, 1)
      k = wordpos(c, special_chars)

      if k \= 0 then
        out = out || word(special_html, k)
      else
        out = out || c

      in = substr(in, 2)
    end
return out

/***********************************************************************
* GET_SOURCE:                                                          *
*                                                                      *
* Read the REXX source                                                 *
***********************************************************************/
get_source:
  macmode = 0
  rxdata. = ''
  rxdata  = ''
  pgm     = ''

  select
    when t_rex = 'TSO' then call get_source_tso
    when t_rex = 'MVS' then call get_source_mvs
    otherwise               call get_source_pc
  end
return

/***********************************************************************
* GET_SOURCE_TSO:                                                      *
*                                                                      *
* Read the text when running under TSO                                 *
***********************************************************************/
get_source_tso:
  if aspace = 'ISPF' then
    "isredit macro (parm) NOPROCESS"
  else
    rc = 4

  /*********************************************************************
  * Running as edit macro                                              *
  *********************************************************************/
  if rc = 0 then
    do
      macmode = 1

      if parm = '?' then
        do
          "isredit ehihelp" moi
          exit
        end

      "isredit process range HI"
      if rc <= 4 then
        do
          "isredit (ZF) = linenum .zfrange"
          "isredit (ZL) = linenum .zlrange"
        end
      else
        do
          "isredit ehihelp" moi
          exit
        end

      "isredit (DSN) = dataset"
      "isredit (MEM) = member"

      if mem = '' then
        idsn = "'" || dsn || "'"
      else
        do
          pgm  = mem
          idsn = "'" || dsn || '(' || mem || ")'"
        end

      /*****************************************************************
      * Concatenate the full source, but indicate original line breaks *
      *****************************************************************/
      i = 0
      do j = +zf to +zl
        "isredit (DATALINE) = line" j

        i        = i + 1
        rxdata.i = strip(dataline, 'T') || ' ' || '0d0a'x
      end

      rxdata.0 = i
      olines   = rxdata.0
    end
  /*********************************************************************
  * Running as TSO command                                             *
  *********************************************************************/
  else
    do
      if idsn = '' then
        do
          msg =     left('Error - No dataset name passed', 75)
          msg = msg left(moi 'can be used as an edit macro or',
                         'as a line command on the ISPF', 75)
          msg = msg left('dataset list utility. In both cases the',
                         'dataset name will be automatically', 75)
          msg = msg left('determined.', 75)
          msg = msg left('If you call' moi 'on the command line you',
                         'have to pass the name of the', 75)
          msg = msg left('dataset to be processed, e.g.', 75)
          msg = msg left('Command ===>' moi,
                         '''my.rexx.dataset(test)''', 75)

          zedsmsg = ''
          zedlmsg = msg

          if t_rex  = 'TSO'  &,
             aspace = 'ISPF' &,
             envir \= 'BATCH' then
            "ispexec setmsg msg(ISRZ001)"
          else
            do while msg \= ''
              say left(msg, 75)
              msg = substr(msg, 76)
            end

          exit 8
        end

      /*****************************************************************
      * Force single quotes around dataset name and check if it's OK   *
      *****************************************************************/
      idsn = "'" || strip(idsn,, '''') || "'"

      if sysdsn(idsn) \= 'OK' then
        do
          say 'Error - Dataset' idsn 'could not be found'
          exit 8
        end

      /*****************************************************************
      * Extract member name, if present                                *
      *****************************************************************/
      parse var idsn . '(' mem ')'

      if mem \= '' then
        pgm = mem

      /*****************************************************************
      * Read the code                                                  *
      *****************************************************************/
      dynlib = 'dyn'random(99999)

      "alloc f("dynlib") da("idsn") shr reu"
      if rc > 0 then
        do
          say 'Error - Dataset' idsn 'could not be allocated - rc' rc
          exit 8
        end

      "execio * diskr" dynlib "(finis)"
      if rc > 0 then
        do
          say 'Error - Dataset' idsn 'could not be read - rc' rc
          exit 8
        end

      "free f("dynlib")"

      /*****************************************************************
      * Merge full source, indicating linebreaks                       *
      *****************************************************************/
      olines = queued()

      i = 0
      do queued()
        parse pull dataline

        if length(dataline) = 80 &,
           datatype(right(dataline, 8)) = 'NUM' then
          dataline = substr(dataline, 1, 72)

        i        = i + 1
        rxdata.i = strip(dataline, 'T') || ' ' || '0d0a'x
      end
    end
return

/***********************************************************************
* GET_SOURCE_PC:                                                       *
*                                                                      *
* Read the text when running on the PC                                 *
***********************************************************************/
get_source_pc:
  if idsn = '' then
    do
      say 'Syntax:' moi 'file.rex'
      exit 8
    end

  do i = 1 by 1 while lines(idsn)
    dataline = linein(idsn)

    if length(dataline) = 80 &,
       datatype(right(dataline, 8)) = 'NUM' then
      dataline = substr(dataline, 1, 72)

    rxdata.i = strip(dataline, 'T') || ' ' || '0d0a'x
  end

  rxdata.0 = i - 1
  olines   = rxdata.0
return

/***********************************************************************
* INIT_VARS:                                                           *
*                                                                      *
* This procedure initialises the global variables                      *
***********************************************************************/
init_vars:
  /*********************************************************************
  * Parameter separator for EHISUPP exec                               *
  *********************************************************************/
  sep = x2c(00)d2c(random(2**16))x2c(ff)d2c(random(2**16))x2c(00)
  sep = translate(sep, x2c(bababababa), ' <>&"')

  /*********************************************************************
  * Get processing options                                             *
  *********************************************************************/
  opt = ehisupp('get_options,'sep','moi)
  parse value opt with view_html     (sep),
                       xfer_wsa      (sep),
                       start_browser (sep),
                       ispf_edit     (sep),
                       show_progress (sep),
                       dir_pc        (sep),
                       htmlfont      (sep),
                       ipaddr        (sep) .

  /*********************************************************************
  * Temporary output dataset                                           *
  *********************************************************************/
  if mem \= '' then
    odsn = "'" || userid() || '.' || mem || ".exec.html'"
  else
    odsn = "'" || userid() || '.' || moi || ".exec.html'"

  /*********************************************************************
  * Text strings for title, header and footer                          *
  *********************************************************************/
  title  = 'REXX exec:' strip(idsn,, '''')
  header = 'REXX exec:' strip(idsn,, '''')
  now    = date('S')
  now    = left(now, 4)'-'substr(now, 5, 2)'-'right(now, 2)'T'time()
  footer = 'Generated on' now 'by' userid() 'with' moi

  /*********************************************************************
  * Name of generated html file on PC                                  *
  *********************************************************************/
  if pgm \= '' then
    htmlfile = pgm || '.html'
  else
    htmlfile = 'rexxpgm.html'

  /*********************************************************************
  * HTML colors                                                        *
  *                                                                    *
  * - lime(green) - default                                            *
  * - red         - keywords                                           *
  * - white       - quoted strings                                     *
  * - aqua(turq)  - comments                                           *
  * - yellow      - special characters                                 *
  *********************************************************************/
  col_dft        = '<em class="l">'                        /* lime    */
  col_key        = '<em class="r">'                        /* red     */
  col_str        = '<em class="w">'                        /* white   */
  col_com        = '<em class="t">'                        /* turq    */
  col_spc        = '<em class="y">'                        /* yellow  */

  /*********************************************************************
  * Colors for nested parentheses                                      *
  *********************************************************************/
  col_par.0      = '<em class="f">'                        /* fuchsia */
  col_par.1      = '<em class="y">'                        /* yellow  */
  col_par.2      = '<em class="w">'                        /* white   */
  col_par.3      = '<em class="r">'                        /* red     */
  col_par.4      = '<em class="t">'                        /* turq    */

  /*********************************************************************
  * HTML special characters and their defined entities                 *
  *********************************************************************/
  special_chars  = 'ä ö ü Ä Ö Ü ß < > & " ¢'
  special_html   = '&auml; &ouml; &uuml; &Auml; &Ouml; &Uuml; &szlig;',
                   '&lt; &gt; &amp; &quot; &cent;'

  /*********************************************************************
  * Characters to be highlighted                                       *
  *********************************************************************/
  special_hilite = '+-*/=<>&^|:%\'

  /*********************************************************************
  * Characters separating words                                        *
  *********************************************************************/
  separator      = " (=*-+/^%)&|<>'" || '"'
return

/***********************************************************************
* BUILD_HTML:                                                          *
*                                                                      *
* This procedure builds the HTML output                                *
***********************************************************************/
build_html:
  /*********************************************************************
  * Load the list of REXX keywords, builtins, etc                      *
  *********************************************************************/
  call build_list_of_keywords

  /*********************************************************************
  * Switches                                                           *
  *********************************************************************/
  kwbegin  = 1                  /* Do we expect a new keyword ?       */

  in_com   = 0                  /* Inside a comment                   */
  in_apost = 0                  /* Inside a '(apost) delimited string */
  in_quote = 0                  /* Inside a "(quote) delimited string */
  level    = 0                  /* Nested comment levels              */
  paren    = 1                  /* Nested parentheses level           */

  /*********************************************************************
  * Initialize the html output string                                  *
  *********************************************************************/
  if ispf_edit = 'ISPF' then
    htmlout = x2c(ff)ispf_edit || x2c(ff)right(olines, 6, '0')x2c(ff)
  else
    htmlout = ''

  tempout = ''

  /*********************************************************************
  * Loop over the code                                                 *
  *********************************************************************/
  lip = time('E')
  lip = 1

  r      = 1
  rxdata = rxdata.r

  do until rxdata == ''
    /*******************************************************************
    * Display (optional) progress messages                             *
    *******************************************************************/
    if show_progress > 0 then
      if lip >                  0 &,
         lip // show_progress = 0 then
        do
          progress = 'Elapsed time' right(time('E'), 12),
                     '- lines processed' right(lip, 6)

          if t_rex  = 'TSO'  &,
             aspace = 'ISPF' then
            rc = ehisupp('monitor,'moi 'Progress,'progress)
          else
            say progress

          lip = -lip
        end

    c1 = left(rxdata, 1)
    c2 = left(rxdata, 2)

    /*******************************************************************
    * Is it a special character?                                       *
    *******************************************************************/
    sc = wordpos(c1, special_chars)

    /*******************************************************************
    * Is it a special hilite character?                                *
    *******************************************************************/
    sh = pos(c1, special_hilite)

    kw = ''                                     /* Initialize keyword */

    /*******************************************************************
    * If we are at the beginning of a keyword ...                      *
    *******************************************************************/
    if kwbegin            = 1 &,
       pos(c1, separator) = 0 then
      do
        parse upper var rxdata kw

        /***************************************************************
        * ... we search the next separator ...                         *
        ***************************************************************/
        sep_pos = verify(kw, separator, 'M')

        /***************************************************************
        * ... and save the keyword if separator is found               *
        ***************************************************************/
        if sep_pos > 0 then
          kw = left(kw, sep_pos - 1)

        kwbegin = 0
      end
    /*******************************************************************
    * If we are on a separator we keep in mind that it's the beginning *
    * of a new keyword                                                 *
    *******************************************************************/
    if pos(c1, separator) > 0 then
      kwbegin = 1

    /*******************************************************************
    * Determine the HTML attributes for the data                       *
    *******************************************************************/
    select
      /*****************************************************************
      * Spaces are kept unchanged - process multiple spaces in one go| *
      *****************************************************************/
      when c1 == ' ' then
        do
          n       = verify(rxdata, ' ')
          tempout = tempout || left(rxdata, n - 1)
          rxdata  = substr(rxdata, n)
        end

      /*****************************************************************
      * Line break                                                     *
      *****************************************************************/
      when c2 = '0d0a'x then
        do
          lip     = abs(lip) + 1
          tempout = tempout || '<br>'
          kwbegin = 1
          rxdata  = substr(rxdata, 3)
        end

      /*****************************************************************
      * End of single quoted string                                    *
      *****************************************************************/
      when in_apost &,
           c1 = "'" then
        do
          in_apost = 0

          tempout  = tempout || "'</em>"
          rxdata   = substr(rxdata, 2)
        end

      /*****************************************************************
      * End of double quoted string                                    *
      *****************************************************************/
      when in_quote &,
           c1 = '"' then
        do
          in_quote = 0

          tempout  = tempout || '"</em>'
          rxdata   = substr(rxdata, 2)
        end

      /*****************************************************************
      * Start of single quoted string                                  *
      *****************************************************************/
      when c1 = "'"  &,
           \in_quote &,
           \in_com then
        do
          in_apost = 1

          tempout  = tempout || col_str"'"
          rxdata   = substr(rxdata, 2)
        end

      /*****************************************************************
      * Start of double quoted string                                  *
      *****************************************************************/
      when c1 = '"'  &,
           \in_apost &,
           \in_com then
        do
          in_quote = 1

          tempout  = tempout || col_str'"'
          rxdata   = substr(rxdata, 2)
        end

      /*****************************************************************
      * Start of a nested comment                                      *
      *****************************************************************/
      when c2 = '/*' &,
           in_com then
        do
          level   = level + 1
          tempout = tempout || '/*'
          rxdata  = substr(rxdata, 3)
        end

      /*****************************************************************
      * Start of a comment                                             *
      *****************************************************************/
      when c2 = '/*' &,
           \in_apost &,
           \in_quote then
        do
          in_com  = 1

          tempout = tempout || col_com'/*'
          rxdata  = substr(rxdata, 3)
        end

      /*****************************************************************
      * End of a comment                                               *
      *****************************************************************/
      when c2    = '*/' &,
           level = 0    &,
           \in_apost    &,
           \in_quote then
        do
          in_com  = 0

          tempout = tempout || '*/</em>'
          rxdata  = substr(rxdata, 3)
        end

      /*****************************************************************
      * End of a nested comment                                        *
      *****************************************************************/
      when c2 = '*/' &,
           \in_apost &,
           \in_quote then
        do
          level   = level - 1
          tempout = tempout || '*/'
          rxdata  = substr(rxdata, 3)
        end

      /*****************************************************************
      * A special character has to be translated and highlighted       *
      *****************************************************************/
      when sc > 0    &,
           sh > 0    &,
           \in_com   &,
           \in_apost &,
           \in_quote then
        do
          tempout = tempout || col_spc || word(special_html, sc)'</em>'
          rxdata  = substr(rxdata, 2)
        end

      /*****************************************************************
      * A special character has to be translated                       *
      *****************************************************************/
      when sc > 0 then
        do
          tempout = tempout || word(special_html, sc)
          rxdata  = substr(rxdata, 2)
        end

      /*****************************************************************
      * A special character has to be highlighted                      *
      *****************************************************************/
      when sh > 0    &,
           \in_com   &,
           \in_apost &,
           \in_quote then
        do
          tempout = tempout || col_spc || c1'</em>'
          rxdata  = substr(rxdata, 2)
        end

      /*****************************************************************
      * It's a keyword                                                 *
      *****************************************************************/
      when keyword.kw = 1 &,
           \in_com        &,
           \in_apost      &,
           \in_quote then
        do
          kw      = left(rxdata, length(kw))
          tempout = tempout || col_key || kw'</em>'
          rxdata  = substr(rxdata, length(kw) + 1)
        end

      /*****************************************************************
      * It's a left parenthesis                                        *
      *****************************************************************/
      when c1 = '('  &,
           \in_com   &,
           \in_apost &,
           \in_quote then
        do
          paren   = (paren + 1) // 5
          tempout = tempout || col_par.paren'(</em>'
          rxdata  = substr(rxdata, 2)
        end

      /*****************************************************************
      * It's a right parenthesis                                       *
      *****************************************************************/
      when c1 = ')'  &,
           \in_com   &,
           \in_apost &,
           \in_quote then
        do
          tempout = tempout || col_par.paren')</em>'
          paren   = (paren + 4) // 5
          rxdata  = substr(rxdata, 2)
        end

      /*****************************************************************
      * Anything else                                                  *
      *****************************************************************/
      otherwise
        do
          tempout = tempout || c1
          rxdata  = substr(rxdata, 2)
        end
    end

    /*******************************************************************
    * Get more data                                                    *
    *******************************************************************/
    if length(rxdata) < 80 then
      do
        r       = r + 1
        rxdata  = rxdata || rxdata.r
      end

    /*******************************************************************
    * Append data to final result                                      *
    *******************************************************************/
    if length(tempout) > 512 then
      do
        htmlout = htmlout || tempout
        tempout = ''
      end
  end

  htmlout = htmlout || tempout
return

/***********************************************************************
* BUILD_LIST_OF_KEYWORDS:                                              *
*                                                                      *
* This procedure loads the list of REXX keywords                       *
***********************************************************************/
build_list_of_keywords:
  keyword. = 0

  /*********************************************************************
  * These three variables have values|                                 *
  *********************************************************************/
  drop rc sigl source

  /*********************************************************************
  * Keyword Instructions                                               *
  *********************************************************************/
  keyword.ADDRESS     = 1
  keyword.ARG         = 1
  keyword.BY          = 1
  keyword.CALL        = 1
  keyword.DO          = 1
  keyword.DROP        = 1
  keyword.ELSE        = 1
  keyword.END         = 1
  keyword.ERROR       = 1
  keyword.EXIT        = 1
  keyword.EXPOSE      = 1
  keyword.FOR         = 1
  keyword.FOREVER     = 1
  keyword.FAILURE     = 1
  keyword.HALT        = 1
  keyword.IF          = 1
  keyword.INTERPRET   = 1
  keyword.ITERATE     = 1
  keyword.LEAVE       = 1
  keyword.NOP         = 1
  keyword.NUMERIC     = 1
  keyword.OFF         = 1
  keyword.OTHERWISE   = 1
  keyword.ON          = 1
  keyword.PARSE       = 1
  keyword.PROCEDURE   = 1
  keyword.PULL        = 1
  keyword.PUSH        = 1
  keyword.QUEUE       = 1
  keyword.RC          = 1
  keyword.RESULT      = 1
  keyword.RETURN      = 1
  keyword.SAY         = 1
  keyword.SCIENTIFIC  = 1
  keyword.SELECT      = 1
  keyword.SIGL        = 1
  keyword.SIGNAL      = 1
  keyword.SOURCE      = 1
  keyword.SYNTAX      = 1
  keyword.THEN        = 1
  keyword.TO          = 1
  keyword.TRACE       = 1
  keyword.UNTIL       = 1
  keyword.UPPER       = 1
  keyword.VAR         = 1
  keyword.VERSION     = 1
  keyword.WHEN        = 1
  keyword.WHILE       = 1
  keyword.WITH        = 1

  /*********************************************************************
  * Built-in Functions                                                 *
  *********************************************************************/
  keyword.ABBREV      = 1
  keyword.ABS         = 1
  keyword.ADDRESS     = 1
  keyword.ARG         = 1
  keyword.BITAND      = 1
  keyword.BITOR       = 1
  keyword.BITXOR      = 1
  keyword.B2X         = 1
  keyword.CENTER      = 1
  keyword.CENTRE      = 1
  keyword.COMPARE     = 1
  keyword.CONDITION   = 1
  keyword.COPIES      = 1
  keyword.C2D         = 1
  keyword.C2X         = 1
  keyword.DATATYPE    = 1
  keyword.DATE        = 1
  keyword.DELSTR      = 1
  keyword.DELWORD     = 1
  keyword.DIGITS      = 1
  keyword.D2C         = 1
  keyword.D2X         = 1
  keyword.ERRORTEXT   = 1
  keyword.FIND        = 1
  keyword.FORM        = 1
  keyword.FORMAT      = 1
  keyword.FUZZ        = 1
  keyword.INDEX       = 1
  keyword.INSERT      = 1
  keyword.JUSTIFY     = 1
  keyword.LASTPOS     = 1
  keyword.LEFT        = 1
  keyword.LENGTH      = 1
  keyword.LINESIZE    = 1
  keyword.MAX         = 1
  keyword.MIN         = 1
  keyword.OVERLAY     = 1
  keyword.POS         = 1
  keyword.QUEUED      = 1
  keyword.RANDOM      = 1
  keyword.REVERSE     = 1
  keyword.RIGHT       = 1
  keyword.SIGN        = 1
  keyword.SOURCELINE  = 1
  keyword.SPACE       = 1
  keyword.STRIP       = 1
  keyword.SUBSTR      = 1
  keyword.SUBWORD     = 1
  keyword.SYMBOL      = 1
  keyword.TIME        = 1
  keyword.TRACE       = 1
  keyword.TRANSLATE   = 1
  keyword.TRUNC       = 1
  keyword.USERID      = 1
  keyword.VALUE       = 1
  keyword.VERIFY      = 1
  keyword.WORD        = 1
  keyword.WORDINDEX   = 1
  keyword.WORDLENGTH  = 1
  keyword.WORDPOS     = 1
  keyword.WORDS       = 1
  keyword.XRANGE      = 1
  keyword.X2B         = 1
  keyword.X2C         = 1
  keyword.X2D         = 1

  /*********************************************************************
  * TSO/E External Functions                                           *
  *********************************************************************/
  keyword.EXTERNALS   = 1
  keyword.FIND        = 1
  keyword.GETMSG      = 1
  keyword.INDEX       = 1
  keyword.JUSTIFY     = 1
  keyword.LINESIZE    = 1
  keyword.LISTDSI     = 1
  keyword.MSG         = 1
  keyword.MVSVAR      = 1
  keyword.OUTTRAP     = 1
  keyword.PROMPT      = 1
  keyword.SETLANG     = 1
  keyword.STORAGE     = 1
  keyword.SYSCPUS     = 1
  keyword.SYSDSN      = 1
  keyword.SYSVAR      = 1
  keyword.USERID      = 1

  /*********************************************************************
  * DBCS Functions - only DBCS is HILITE'd on ISPF 5.7.0000            *
  *********************************************************************/
  keyword.DBADJUST    = 1
  keyword.DBBRACKET   = 1
  keyword.DBCENTER    = 1
  keyword.DBCJUSTIFY  = 1
  keyword.DBCS        = 1
  keyword.DBLEFT      = 1
  keyword.DBRIGHT     = 1
  keyword.DBRLEFT     = 1
  keyword.DBRRIGHT    = 1
  keyword.DBTODBCS    = 1
  keyword.DBTOSBCS    = 1
  keyword.DBUNBRACKET = 1
  keyword.DBVALIDATE  = 1
  keyword.DBWIDTH     = 1

  /*********************************************************************
  * TSO/E REXX Commands - not HILITE'd on ISPF 5.7.0000...             *
  *********************************************************************/
  keyword.DELSTACK    = 1
  keyword.DROPBUF     = 1
  keyword.EXECIO      = 1
  keyword.EXECUTIL    = 1
  keyword.HE          = 1
  keyword.HI          = 1
  keyword.HT          = 1
  keyword.MAKEBUF     = 1
  keyword.NEWSTACK    = 1
  keyword.QBUF        = 1
  keyword.QELEM       = 1
  keyword.QSTACK      = 1
  keyword.RT          = 1
  keyword.SUBCOM      = 1
  keyword.TE          = 1
  keyword.TS          = 1
return