/* REXX exec/edit macro to convert PL/I to 'HILITE'd HTML             */
/*** trace ?r ***************************************************** \| *
*               (C) Copyright Robert AH Prins, 2007-2016               *
************************************************************************
*  ------------------------------------------------------------------  *
* | Date       | By   | Remarks                                      | *
* |------------+------+----------------------------------------------| *
* |            |      |                                              | *
* |------------+------+----------------------------------------------| *
* | 2016-11-18 | RAHP | Multiple updates/simplifications             | *
* |------------+------+----------------------------------------------| *
* | 2015-08-19 | RAHP | Additional V4R4 & V4R5 keywords              | *
* |------------+------+----------------------------------------------| *
* | 2012-10-08 | RAHP | - parse *process not() and *process or() for | *
* |            |      |   additional characters to highlight         | *
* |            | RAHP | - additional V4R3 keywords                   | *
* |------------+------+----------------------------------------------| *
* | 2012-06-25 | RAHP | Add IP address                               | *
* |------------+------+----------------------------------------------| *
* | 2012-04-30 | RAHP | Additional V4R2 keywords                     | *
* |------------+------+----------------------------------------------| *
* | 2010-09-30 | RAHP | Additional V4R1 keyword                      | *
* |------------+------+----------------------------------------------| *
* | 2010-08-23 | RAHP | - keyword can start after ASA character      | *
* |            |      | - correct keyword intro versions             | *
* |------------+------+----------------------------------------------| *
* | 2010-08-02 | RAHP | Add V3R9 and V4R1 keywords                   | *
* |------------+------+----------------------------------------------| *
* | 2009-08-20 | RAHP | Additional keyword                           | *
* |------------+------+----------------------------------------------| *
* | 2009-07-27 | RAHP | Use pop-up on ISPF to display progress       | *
* |------------+------+----------------------------------------------| *
* | 2009-07-02 | RAHP | Add selection for short CSS 'em' colors      | *
* |------------+------+----------------------------------------------| *
* | 2009-06-22 | RAHP | - accept %process statements                 | *
* |            |      | - correct name of builtin                    | *
* |------------+------+----------------------------------------------| *
* | 2009-04-30 | RAHP | Disable nested comment processing            | *
* |------------+------+----------------------------------------------| *
* | 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-03-23 | RAHP | Add Enterprise PL/I V3.8.0 keywords          | *
* |------------+------+----------------------------------------------| *
* | 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 | Initial version (copy of EHIREXX)            | *
* |------------+------+----------------------------------------------| *
************************************************************************
* EHIPLI is a REXX exec/edit macro that analyses PL/I 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.    *
*                                                                      *
* 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 PL/I 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

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 PL/I 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

        if left(dataline, 1) \= ' ' then
          dataline = left(dataline, 1)x2c(00)substr(dataline, 2)

        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.pli.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)

        if left(dataline, 1) \= ' ' then
          dataline = left(dataline, 1)x2c(00)substr(dataline, 2)

        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.pli'
      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)

    if left(dataline, 1) \= ' ' then
      dataline = left(dataline, 1)x2c(00)substr(dataline, 2)

    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 || ".pli.html'"
  else
    odsn = "'" || userid() || '.' || moi || ".pli.html'"

  /*********************************************************************
  * Text strings for title, header and footer                          *
  *********************************************************************/
  title  = 'PL/I source:' strip(idsn,, '''')
  header = 'PL/I source:' 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 = 'plipgm.html'

  /*********************************************************************
  * HTML colors                                                        *
  *                                                                    *
  * - lime(green) - default                                            *
  * - red         - keywords                                           *
  * - white       - quoted strings                                     *
  * - aqua(turq)  - comments                                           *
  * - yellow      - special characters                                 *
  * - blue        - pre-processor code                                 *
  *********************************************************************/
  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  */
  col_pre        = '<em class="b">'                        /* blue    */

  /*********************************************************************
  * 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   = '&lt; &gt; &amp; &quot;'

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

  /*********************************************************************
  * Characters separating words                                        *
  *********************************************************************/
  separator      = ' +-*/=<>&^|.,:;''()"'x2c(00)
return

/***********************************************************************
* BUILD_HTML:                                                          *
*                                                                      *
* This procedure builds the HTML output                                *
***********************************************************************/
build_html:
  /*********************************************************************
  * Load the list of PL/I 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 */
  in_pro   = 0                  /* Inside a *process directive        */
  in_pre   = 0                  /* Inside a %pre-processor statement  */
  level    = 0                  /* Nested comment levels              */
  paren    = 1                  /* Nested parentheses level           */
  nest_com = 0                  /* No nested comments in PL/I (yet)   */

  /*********************************************************************
  * 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
      /*****************************************************************
      * It's an ASA control character                                  *
      *****************************************************************/
      when c1          \= '*' &,
           c1          \= '%' &,
           right(c2, 1) = x2c(00) then
        do
          tempout = tempout || col_spc || c1'</em>'
          rxdata  = substr(rxdata, 3)
          kwbegin = 1
        end

      /*****************************************************************
      * 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 + nest_com
          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 - nest_com
          tempout = tempout || '*/'
          rxdata  = substr(rxdata, 3)
        end

      /*****************************************************************
      * A special character has to be translated and highlighted       *
      *****************************************************************/
      when sc > 0    &,
           sh > 0    &,
           \in_pro   &,
           \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

      /*****************************************************************
      * It's a *process or %process statement                          *
      *****************************************************************/
      when (c1          = '*'     |,
            c1          = '%')    &,
           right(c2, 1) = x2c(00) &,
           \in_pro   &,
           \in_com   &,
           \in_apost &,
           \in_quote then
        do
          in_pro  = 1
          tempout = tempout || col_pre || c1
          rxdata  = substr(rxdata, 3)
          ruxdata = translate(rxdata)

          /*************************************************************
          * Get special NOT and OR characters from *process            *
          *************************************************************/
          if pos("NOT('", ruxdata) \= 0 then
            do
              parse value ruxdata with . "NOT('" ?spc ")" .

              special_hilite = special_hilite || ?spc
              separator      = ?spc || separator
            end

          if pos("OR('", ruxdata) \= 0 then
            do
              parse value ruxdata with . "OR('" ?spc ")" .

              special_hilite = special_hilite || ?spc
              separator      = ?spc || separator
            end
        end

      /*****************************************************************
      * A special character has to be highlighted                      *
      *****************************************************************/
      when sh > 0    &,
           \in_pre   &,
           \in_pro   &,
           \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_pro        &,
           \in_pre        &,
           \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 pre-processor directive (%)                             *
      *****************************************************************/
      when c1 = '%'  &,
           \in_pro   &,
           \in_pre   &,
           \in_com   &,
           \in_apost &,
           \in_quote then
        do
          in_pre  = 1
          tempout = tempout || col_pre'%'
          rxdata  = substr(rxdata, 2)
        end

      /*****************************************************************
      * It's a left parenthesis                                        *
      *****************************************************************/
      when c1 = '('  &,
           \in_pro   &,
           \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_pro   &,
           \in_com   &,
           \in_apost &,
           \in_quote then
        do
          tempout = tempout || col_par.paren')</em>'
          paren   = (paren + 4) // 5
          rxdata  = substr(rxdata, 2)
        end

      /*****************************************************************
      * It's a semi-colon while in a pre-processor state               *
      *****************************************************************/
      when c1 = ';'  &,
          (in_pre    |,
           in_pro)   &,
           \in_com   &,
           \in_apost &,
           \in_quote then
        do
          in_pre  = 0
          in_pro  = 0
          tempout = tempout || ';</em>'
          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 PL/I keywords                       *
***********************************************************************/
build_list_of_keywords:
  keyword. = 0

  keyword.ABNORMAL               = 1
  keyword.ABS                    = 1
  keyword.ACOS                   = 1
  keyword.ACOSF                  = 1
  keyword.ADD                    = 1
  keyword.ADDBUFF                = 1
  keyword.ADDR                   = 1
  keyword.ADDRDATA               = 1
  keyword.ALIAS                  = 1
  keyword.ALIGNED                = 1
  keyword.ALL                    = 1
  keyword.ALLCOMPARE             = 1                        /* EP 4.3 */
  keyword.ALLOC                  = 1
  keyword.ALLOCATE               = 1
  keyword.ALLOCATION             = 1
  keyword.ALLOCN                 = 1
  keyword.ALLOCSIZE              = 1
  keyword.ALLOC31                = 1                        /* EP 5.1 */
  keyword.ANY                    = 1
  keyword.ANYCONDITION           = 1
  keyword.AREA                   = 1
  keyword.ASCII                  = 1
  keyword.ASIN                   = 1
  keyword.ASINF                  = 1
  keyword.ASM                    = 1
  keyword.ASMTDLI                = 1
  keyword.ASSEMBLER              = 1
  keyword.ASSERT                 = 1                        /* EP 4.3 */
  keyword.ASSIGNABLE             = 1
  keyword.ATAN                   = 1
  keyword.ATAND                  = 1
  keyword.ATANF                  = 1
  keyword.ATANH                  = 1
  keyword.ATTACH                 = 1
  keyword.ATTENTION              = 1
  keyword.ATTN                   = 1
  keyword.AUTO                   = 1
  keyword.AUTOMATIC              = 1
  keyword.AVAILABLEAREA          = 1
  keyword.BACKWARDS              = 1
  keyword.BASED                  = 1
  keyword.BASE64DECODE16         = 1                        /* EP 4.4 */
  keyword.BASE64DECODE8          = 1                        /* EP 4.4 */
  keyword.BASE64ENCODE16         = 1                        /* EP 4.4 */
  keyword.BASE64ENCODE8          = 1                        /* EP 4.4 */
  keyword.BEGIN                  = 1
  keyword.BETWEEN                = 1                        /* EP 4.5 */
  keyword.BETWEENEXCLUSIVE       = 1                        /* EP 5.1 */
  keyword.BETWEENLEFTEXCCLUSIVE  = 1                        /* EP 5.1 */
  keyword.BETWEENRIGHtEXCCLUSIVE = 1                        /* EP 5.1 */
  keyword.BIGENDIAN              = 1
  keyword.BIN                    = 1
  keyword.BINARY                 = 1
  keyword.BINARYVALUE            = 1
  keyword.BIND                   = 1
  keyword.BINVALUE               = 1
  keyword.BIT                    = 1
  keyword.BITLOC                 = 1
  keyword.BITLOCATION            = 1
  keyword.BKWD                   = 1
  keyword.BLKSIZE                = 1
  keyword.BOOL                   = 1
  keyword.BUF                    = 1
  keyword.BUFFERED               = 1
  keyword.BUFFERS                = 1
  keyword.BUFND                  = 1
  keyword.BUFNI                  = 1
  keyword.BUFOFF                 = 1
  keyword.BUFSP                  = 1
  keyword.BUILTIN                = 1
  keyword.BX                     = 1
  keyword.BY                     = 1
  keyword.BYADDR                 = 1
  keyword.BYTE                   = 1
  keyword.BYVALUE                = 1
  keyword.B4                     = 1
  keyword.CALL                   = 1
  keyword.CANCEL                 = 1                        /* EP 4.4 */
  keyword.CAST                   = 1
  keyword.CDS                    = 1
  keyword.CEIL                   = 1
  keyword.CENTER                 = 1
  keyword.CENTERLEFT             = 1
  keyword.CENTERRIGHT            = 1
  keyword.CENTRE                 = 1
  keyword.CENTRELEFT             = 1
  keyword.CENTRERIGHT            = 1
  keyword.CHAR                   = 1
  keyword.CHARACTER              = 1
  keyword.CHARG                  = 1
  keyword.CHARGRAPHIC            = 1
  keyword.CHARVAL                = 1
  keyword.CHECK                  = 1
  keyword.CHECKSTG               = 1
  keyword.CHECKSUM               = 1                        /* EP 5.1 */
  keyword.CLOSE                  = 1
  keyword.CMPAT                  = 1
  keyword.COBOL                  = 1
  keyword.COL                    = 1
  keyword.COLLATE                = 1
  keyword.COLUMN                 = 1
  keyword.COMMENT                = 1
  keyword.COMPARE                = 1
  keyword.COMPILEDATE            = 1
  keyword.COMPILETIME            = 1
  keyword.COMPLETION             = 1
  keyword.COMPLEX                = 1
  keyword.COND                   = 1
  keyword.CONDITION              = 1
  keyword.CONJG                  = 1
  keyword.CONN                   = 1
  keyword.CONNECTED              = 1
  keyword.CONSECUTIVE            = 1
  keyword.CONTROLLED             = 1
  keyword.CONV                   = 1
  keyword.CONVERSION             = 1
  keyword.COPY                   = 1
  keyword.COS                    = 1
  keyword.COSD                   = 1
  keyword.COSF                   = 1
  keyword.COSH                   = 1
  keyword.COUNT                  = 1
  keyword.COUNTER                = 1
  keyword.CPLN                   = 1
  keyword.CPLX                   = 1
  keyword.CS                     = 1
  keyword.CSTG                   = 1
  keyword.CTL                    = 1
  keyword.CTLASA                 = 1
  keyword.CTL360                 = 1
  keyword.CURRENTSIZE            = 1
  keyword.CURRENTSTORAGE         = 1
  keyword.DATA                   = 1
  keyword.DATAFIELD              = 1
  keyword.DATE                   = 1
  keyword.DATETIME               = 1
  keyword.DAYS                   = 1
  keyword.DAYSTODATE             = 1
  keyword.DAYSTOSECS             = 1
  keyword.DB                     = 1
  keyword.DCL                    = 1
  keyword.DEC                    = 1
  keyword.DECIMAL                = 1
  keyword.DECLARE                = 1
  keyword.DEF                    = 1
  keyword.DEFAULT                = 1
  keyword.DEFINE                 = 1
  keyword.DEFINED                = 1
  keyword.DELAY                  = 1
  keyword.DELETE                 = 1
  keyword.DESCRIPTOR             = 1
  keyword.DESCRIPTORS            = 1
  keyword.DETACH                 = 1
  keyword.DFT                    = 1
  keyword.DIM                    = 1
  keyword.DIMACROSS              = 1                        /* EP 3.8 */
  keyword.DIMENSION              = 1
  keyword.DIRECT                 = 1
  keyword.DISPLAY                = 1
  keyword.DIVIDE                 = 1
  keyword.DO                     = 1
  keyword.DOWNTHRU               = 1
  keyword.EDIT                   = 1
  keyword.ELSE                   = 1
  keyword.EMPTY                  = 1
  keyword.END                    = 1
  keyword.ENDFILE                = 1
  keyword.ENDPAGE                = 1
  keyword.ENTRY                  = 1
  keyword.ENTRYADDR              = 1
  keyword.ENV                    = 1
  keyword.ENVIRONMENT            = 1
  keyword.EPSILON                = 1
  keyword.ERF                    = 1
  keyword.ERFC                   = 1
  keyword.ERROR                  = 1
  keyword.EVENT                  = 1
  keyword.EXCL                   = 1
  keyword.EXCLUSIVE              = 1
  keyword.EXIT                   = 1
  keyword.EXP                    = 1
  keyword.EXPF                   = 1
  keyword.EXPONENT               = 1
  keyword.EXPORTS                = 1
  keyword.EXT                    = 1
  keyword.EXTERNAL               = 1
  keyword.FB                     = 1
  keyword.FBS                    = 1
  keyword.FETCH                  = 1
  keyword.FILE                   = 1
  keyword.FILEDDINT              = 1
  keyword.FILEDDTEST             = 1
  keyword.FILEDDWORD             = 1
  keyword.FILEID                 = 1
  keyword.FILEOPEN               = 1
  keyword.FILEREAD               = 1
  keyword.FILESEEK               = 1
  keyword.FILETELL               = 1
  keyword.FILEWRITE              = 1
  keyword.FINISH                 = 1
  keyword.FIRST                  = 1
  keyword.FIXED                  = 1
  keyword.FIXEDBIN               = 1                        /* EP 3.8 */
  keyword.FIXEDDEC               = 1                        /* EP 3.8 */
  keyword.FIXEDOVERFLOW          = 1
  keyword.FLOAT                  = 1
  keyword.FLOATBIN               = 1                        /* EP 3.8 */
  keyword.FLOATDEC               = 1                        /* EP 3.8 */
  keyword.FLOOR                  = 1
  keyword.FLUSH                  = 1
  keyword.FOFL                   = 1
  keyword.FORMAT                 = 1
  keyword.FORTRAN                = 1
  keyword.FREE                   = 1
  keyword.FROM                   = 1
  keyword.FROMALIEN              = 1
  keyword.FS                     = 1
  keyword.GAMMA                  = 1
  keyword.GENERIC                = 1
  keyword.GENKEY                 = 1
  keyword.GET                    = 1
  keyword.GETENV                 = 1
  keyword.GO                     = 1
  keyword.GOTO                   = 1
  keyword.GRAPHIC                = 1
  keyword.GX                     = 1
  keyword.HANDLE                 = 1
  keyword.HBOUND                 = 1
  keyword.HBOUNDACROSS           = 1                        /* EP 4.2 */
  keyword.HEX                    = 1
  keyword.HEXADEC                = 1
  keyword.HEXDECODE              = 1                        /* EP 5.1 */
  keyword.HEXDECODE8             = 1                        /* EP 5.1 */
  keyword.HEXIMAGE               = 1
  keyword.HIGH                   = 1
  keyword.HUGE                   = 1
  keyword.IAND                   = 1
  keyword.ICLZ                   = 1                        /* EP 5.1 */
  keyword.IEEE                   = 1
  keyword.IEOR                   = 1
  keyword.IF                     = 1
  keyword.IGNORE                 = 1
  keyword.IMAG                   = 1
  keyword.IN                     = 1
  keyword.INDEX                  = 1
  keyword.INDEXAREA              = 1
  keyword.INDEXED                = 1
  keyword.INDEXR                 = 1                        /* EP 4.4 */
  keyword.INDICATORS             = 1                        /* EP 4.2 */
  keyword.INIT                   = 1
  keyword.INITIAL                = 1
  keyword.INLINE                 = 1
  keyword.INLIST                 = 1                        /* EP 4.5 */
  keyword.INONLY                 = 1                        /* EP 3.9 */
  keyword.INOT                   = 1
  keyword.INOUT                  = 1                        /* EP 3.9 */
  keyword.INPUT                  = 1
  keyword.INT                    = 1
  keyword.INTER                  = 1
  keyword.INTERNAL               = 1
  keyword.INTO                   = 1
  keyword.INVALIDOP              = 1
  keyword.IOR                    = 1
  keyword.IRRED                  = 1
  keyword.IRREDUCIBLE            = 1
  keyword.ISFINITE               = 1                        /* EP 3.7 */
  keyword.ISIGNED                = 1
  keyword.ISINF                  = 1                        /* EP 3.7 */
  keyword.ISLL                   = 1
  keyword.ISMAIN                 = 1
  keyword.ISNAN                  = 1                        /* EP 3.7 */
  keyword.ISNORMAL               = 1                        /* EP 3.7 */
  keyword.ISRL                   = 1
  keyword.ISZERO                 = 1                        /* EP 3.7 */
  keyword.IUNSIGNED              = 1
  keyword.JSONGETARRAYEND        = 1                        /* EP 4.5 */
  keyword.JSONGETARRAYSTART      = 1                        /* EP 4.5 */
  keyword.JSONGETCOLON           = 1                        /* EP 4.5 */
  keyword.JSONGETCOMMA           = 1                        /* EP 4.5 */
  keyword.JSONGETMEMBER          = 1                        /* EP 4.5 */
  keyword.JSONGETOBJECTEND       = 1                        /* EP 4.5 */
  keyword.JSONGETOBJECTSTART     = 1                        /* EP 4.5 */
  keyword.JSONGETVALUE           = 1                        /* EP 4.5 */
  keyword.JSONNAME               = 1                        /* EP 5.1 */
  keyword.JSONOMIT               = 1                        /* EP 5.1 */
  keyword.JSONPUTARRAYEND        = 1                        /* EP 4.5 */
  keyword.JSONPUTARRAYSTART      = 1                        /* EP 4.5 */
  keyword.JSONPUTCOLON           = 1                        /* EP 4.5 */
  keyword.JSONPUTCOMMA           = 1                        /* EP 4.5 */
  keyword.JSONPUTMEMBER          = 1                        /* EP 4.5 */
  keyword.JSONPUTOBJECTEND       = 1                        /* EP 4.5 */
  keyword.JSONPUTOBJECTSTART     = 1                        /* EP 4.5 */
  keyword.JSONPUTVALUE           = 1                        /* EP 4.5 */
  keyword.JSONVALID              = 1                        /* EP 4.5 */
  keyword.JULIANTOSMF            = 1                        /* EP 4.5 */
  keyword.KEY                    = 1
  keyword.KEYED                  = 1
  keyword.KEYFROM                = 1
  keyword.KEYLENGTH              = 1
  keyword.KEYLOC                 = 1
  keyword.KEYTO                  = 1
  keyword.LABEL                  = 1
  keyword.LAST                   = 1
  keyword.LBOUND                 = 1
  keyword.LBOUNDACROSS           = 1                        /* EP 4.2 */
  keyword.LEAVE                  = 1
  keyword.LEFT                   = 1
  keyword.LENGTH                 = 1
  keyword.LIKE                   = 1
  keyword.LIMITED                = 1
  keyword.LINE                   = 1
  keyword.LINENO                 = 1
  keyword.LINESIZE               = 1
  keyword.LINKAGE                = 1
  keyword.LIST                   = 1
  keyword.LITTLEENDIAN           = 1
  keyword.LOC                    = 1
  keyword.LOCATE                 = 1
  keyword.LOCATES                = 1                        /* EP 4.4 */
  keyword.LOCATION               = 1
  keyword.LOCNEWSPACE            = 1                        /* EP 4.4 */
  keyword.LOCNEWVALUE            = 1                        /* EP 4.4 */
  keyword.LOCSTG                 = 1                        /* EP 4.4 */
  keyword.LOCVAL                 = 1                        /* EP 4.4 */
  keyword.LOG                    = 1
  keyword.LOGF                   = 1
  keyword.LOGGAMMA               = 1
  keyword.LOG10                  = 1
  keyword.LOG10F                 = 1
  keyword.LOG2                   = 1
  keyword.LOW                    = 1
  keyword.LOWERCASE              = 1
  keyword.LOWER2                 = 1
  keyword.MACCOL                 = 1
  keyword.MACLMAR                = 1
  keyword.MACNAME                = 1
  keyword.MACRMAR                = 1
  keyword.MAIN                   = 1
  keyword.MAINNAME               = 1                        /* EP 5.1 */
  keyword.MAX                    = 1
  keyword.MAXEXP                 = 1
  keyword.MAXLENGTH              = 1
  keyword.MEMCONVERT             = 1                        /* EP 3.7 */
  keyword.MEMCU12                = 1                        /* EP 3.9 */
  keyword.MEMCU14                = 1                        /* EP 3.9 */
  keyword.MEMCU21                = 1                        /* EP 3.9 */
  keyword.MEMCU24                = 1                        /* EP 3.9 */
  keyword.MEMCU41                = 1                        /* EP 3.9 */
  keyword.MEMCU42                = 1                        /* EP 3.9 */
  keyword.MEMINDEX               = 1                        /* EP 3.3 */
  keyword.MEMSEARCH              = 1                        /* EP 3.3 */
  keyword.MEMSEARCHR             = 1                        /* EP 3.3 */
  keyword.MEMVERIFY              = 1                        /* EP 3.3 */
  keyword.MEMVERIFYR             = 1                        /* EP 3.3 */
  keyword.MIN                    = 1
  keyword.MINEXP                 = 1
  keyword.MOD                    = 1
  keyword.MPSTR                  = 1
  keyword.MULTIPLY               = 1
  keyword.NAME                   = 1
  keyword.NATIVE                 = 1
  keyword.NCP                    = 1
  keyword.NEW                    = 1
  keyword.NOCHARG                = 1
  keyword.NOCHARGRAPHIC          = 1
  keyword.NOCHECK                = 1
  keyword.NOCMPAT                = 1
  keyword.NOCONV                 = 1
  keyword.NOCONVERSION           = 1
  keyword.NODESCRIPTOR           = 1
  keyword.NOEXECOPS              = 1
  keyword.NOFIXEDOVERFLOW        = 1
  keyword.NOFOFL                 = 1
  keyword.NOINLINE               = 1
  keyword.NOLOCK                 = 1
  keyword.NOMAP                  = 1
  keyword.NOMAPIN                = 1
  keyword.NOMAPOUT               = 1
  keyword.NONASGN                = 1
  keyword.NONASSIGNABLE          = 1
  keyword.NONCONNECTED           = 1
  keyword.NONNATIVE              = 1
  keyword.NONVAR                 = 1
  keyword.NONVARYING             = 1
  keyword.NOOFL                  = 1
  keyword.NOOVERFLOW             = 1
  keyword.NORESCAN               = 1
  keyword.NORMAL                 = 1
  keyword.NOSIZE                 = 1
  keyword.NOSTRG                 = 1
  keyword.NOSTRINGRANGE          = 1
  keyword.NOSTRINGSIZE           = 1
  keyword.NOSTRZ                 = 1
  keyword.NOSUBRG                = 1
  keyword.NOSUBSCRIPTRANGE       = 1
  keyword.NOUFL                  = 1
  keyword.NOUNDERFLOW            = 1
  keyword.NOWRITE                = 1
  keyword.NOZDIV                 = 1
  keyword.NOZERODIVIDE           = 1
  keyword.NULL                   = 1
  keyword.NULLENTRY              = 1                        /* EP 4.5 */
  keyword.NULLINIT               = 1                        /* EP 4.5 */
  keyword.OFFSET                 = 1
  keyword.OFFSETADD              = 1
  keyword.OFFSETDIFF             = 1
  keyword.OFFSETSUBTRACT         = 1
  keyword.OFFSETVALUE            = 1
  keyword.OFL                    = 1
  keyword.OMITTED                = 1
  keyword.ON                     = 1
  keyword.ONAREA                 = 1                        /* EP 4.1 */
  keyword.ONCHAR                 = 1
  keyword.ONCODE                 = 1
  keyword.ONCONDCOND             = 1
  keyword.ONCONDID               = 1
  keyword.ONCOUNT                = 1
  keyword.ONFILE                 = 1
  keyword.ONGSOURCE              = 1
  keyword.ONKEY                  = 1
  keyword.ONLINE                 = 1                        /* EP 3.8 */
  keyword.ONLOC                  = 1
  keyword.ONOFFSET               = 1                        /* EP 3.7 */
  keyword.ONSOURCE               = 1
  keyword.ONSUBCODE              = 1
  keyword.ONSUBCODE2             = 1                        /* EP 5.1 */
  keyword.ONWCHAR                = 1
  keyword.ONWSOURCE              = 1
  keyword.OPEN                   = 1
  keyword.OPTIONAL               = 1
  keyword.OPTIONS                = 1
  keyword.ORDER                  = 1
  keyword.ORDINAL                = 1
  keyword.ORDINALNAME            = 1
  keyword.ORDINALPRED            = 1
  keyword.ORDINALSUCC            = 1
  keyword.OTHER                  = 1
  keyword.OTHERWISE              = 1
  keyword.OUTONLY                = 1                        /* EP 3.9 */
  keyword.OUTPUT                 = 1
  keyword.OVERFLOW               = 1
  keyword.PACKAGE                = 1
  keyword.PACKAGENAME            = 1
  keyword.PAGE                   = 1
  keyword.PAGENO                 = 1
  keyword.PAGESIZE               = 1
  keyword.PARAMETER              = 1
  keyword.PARMSET                = 1
  keyword.PASSWORD               = 1
  keyword.PENDING                = 1
  keyword.PIC                    = 1
  keyword.PICSPEC                = 1                        /* EP 3.6 */
  keyword.PICTURE                = 1
  keyword.PLACES                 = 1
  keyword.PLIASCII               = 1
  keyword.PLIATTN                = 1                        /* EP 5.1 */
  keyword.PLICANC                = 1                        /* EP 3.2 */
  keyword.PLICKPT                = 1                        /* EP 3.2 */
  keyword.PLIDELETE              = 1
  keyword.PLIDUMP                = 1
  keyword.PLIEBCDIC              = 1
  keyword.PLIFILL                = 1
  keyword.PLIFREE                = 1
  keyword.PLIMOVE                = 1
  keyword.PLIOVER                = 1
  keyword.PLIREST                = 1                        /* EP 3.2 */
  keyword.PLIRETC                = 1
  keyword.PLIRETV                = 1
  keyword.PLISAXA                = 1
  keyword.PLISAXB                = 1
  keyword.PLISAXC                = 1                        /* EP 3.8 */
  keyword.PLISAXD                = 1                        /* EP 4.1 */
  keyword.PLISRTA                = 1
  keyword.PLISRTB                = 1
  keyword.PLISRTC                = 1
  keyword.PLISRTD                = 1
  keyword.PLISTK                 = 1                        /* EP 4.5 */
  keyword.PLISTKE                = 1                        /* EP 4.5 */
  keyword.PLISTKF                = 1                        /* EP 4.5 */
  keyword.PLITDLI                = 1
  keyword.PLITRAN11              = 1                        /* EP 3.9 */
  keyword.PLITRAN12              = 1                        /* EP 3.9 */
  keyword.PLITRAN21              = 1                        /* EP 3.9 */
  keyword.PLITRAN22              = 1                        /* EP 3.9 */
  keyword.POINTER                = 1
  keyword.POINTERADD             = 1
  keyword.POINTERDIFF            = 1
  keyword.POINTERSUBTRACT        = 1
  keyword.POINTERVALUE           = 1
  keyword.POLY                   = 1
  keyword.POPCNT                 = 1                        /* EP 4.2 */
  keyword.POS                    = 1
  keyword.POSITION               = 1
  keyword.PREC                   = 1
  keyword.PRECISION              = 1
  keyword.PRED                   = 1
  keyword.PRESENT                = 1
  keyword.PRINT                  = 1
  keyword.PRIORITY               = 1
  keyword.PROC                   = 1
  keyword.PROCEDURE              = 1
  keyword.PROCEDURENAME          = 1
  keyword.PROCNAME               = 1
  keyword.PROD                   = 1
  keyword.PTR                    = 1
  keyword.PTRADD                 = 1
  keyword.PTRDIFF                = 1
  keyword.PTRSUBTRACT            = 1
  keyword.PTRVALUE               = 1
  keyword.PUT                    = 1
  keyword.PUTENV                 = 1
  keyword.QUOTE                  = 1
  keyword.RADIX                  = 1
  keyword.RAISE2                 = 1
  keyword.RANDOM                 = 1
  keyword.RANGE                  = 1
  keyword.RANK                   = 1
  keyword.READ                   = 1
  keyword.REAL                   = 1
  keyword.RECORD                 = 1
  keyword.RECSIZE                = 1
  keyword.RECURSIVE              = 1
  keyword.RED                    = 1
  keyword.REDUCIBLE              = 1
  keyword.REENTRANT              = 1
  keyword.REFER                  = 1
  keyword.REGIONAL               = 1
  keyword.REG12                  = 1                        /* EP 3.8 */
  keyword.REINIT                 = 1                        /* EP 4.5 */
  keyword.RELEASE                = 1
  keyword.REM                    = 1
  keyword.REORDER                = 1
  keyword.REPATTERN              = 1
  keyword.REPEAT                 = 1
  keyword.REPLACEBY2             = 1                        /* EP 3.4 */
  keyword.REPLY                  = 1
  keyword.REREAD                 = 1
  keyword.RESCAN                 = 1
  keyword.RESERVED               = 1
  keyword.RESERVES               = 1
  keyword.RESIGNAL               = 1
  keyword.RESPEC                 = 1
  keyword.RETCODE                = 1
  keyword.RETURN                 = 1
  keyword.RETURNS                = 1
  keyword.REUSE                  = 1
  keyword.REVERSE                = 1
  keyword.REVERT                 = 1
  keyword.REWRITE                = 1
  keyword.RIGHT                  = 1
  keyword.ROUND                  = 1
  keyword.ROUNDDEC               = 1                        /* EP 3.9 */
  keyword.SAMEKEY                = 1
  keyword.SCALARVARYING          = 1
  keyword.SCALE                  = 1
  keyword.SEARCH                 = 1
  keyword.SEARCHR                = 1
  keyword.SECS                   = 1
  keyword.SECSTODATE             = 1
  keyword.SECSTODAYS             = 1
  keyword.SELECT                 = 1
  keyword.SEQL                   = 1
  keyword.SEQUENTIAL             = 1
  keyword.SERIALIZE4             = 1
  keyword.SET                    = 1
  keyword.SIGN                   = 1
  keyword.SIGNAL                 = 1
  keyword.SIGNED                 = 1
  keyword.SIN                    = 1
  keyword.SIND                   = 1
  keyword.SINF                   = 1
  keyword.SINH                   = 1
  keyword.SIS                    = 1
  keyword.SIZE                   = 1
  keyword.SKIP                   = 1
  keyword.SMFTOJULIAN            = 1                        /* EP 4.5 */
  keyword.SNAP                   = 1
  keyword.SOURCEFILE             = 1
  keyword.SOURCELINE             = 1
  keyword.SQRT                   = 1
  keyword.SQRTF                  = 1
  keyword.STACKADDR              = 1                        /* EP 3.7 */
  keyword.STATEMENT              = 1
  keyword.STATIC                 = 1
  keyword.STATUS                 = 1
  keyword.STG                    = 1
  keyword.STMT                   = 1
  keyword.STOP                   = 1
  keyword.STORAGE                = 1
  keyword.STREAM                 = 1
  keyword.STRG                   = 1
  keyword.STRING                 = 1
  keyword.STRINGRANGE            = 1
  keyword.STRINGSIZE             = 1
  keyword.STRUCTURE              = 1
  keyword.STRZ                   = 1
  keyword.SUBRG                  = 1
  keyword.SUBSCRIPTRANGE         = 1
  keyword.SUBSTR                 = 1
  keyword.SUBTRACT               = 1
  keyword.SUCC                   = 1
  keyword.SUM                    = 1
  keyword.SUPPRESS               = 1                        /* EP 3.8 */
  keyword.SUPPRESS               = 1                        /* EP 5.1 */
  keyword.SYSDIMSIZE             = 1                        /* EP 4.5 */
  keyword.SYSIN                  = 1
  keyword.SYSNULL                = 1
  keyword.SYSOFFSETSIZE          = 1                        /* EP 4.5 */
  keyword.SYSPARM                = 1
  keyword.SYSPOINTERSIZE         = 1                        /* EP 4.5 */
  keyword.SYSPRINT               = 1
  keyword.SYSTEM                 = 1
  keyword.SYSVERSION             = 1
  keyword.TALLY                  = 1
  keyword.TAN                    = 1
  keyword.TAND                   = 1
  keyword.TANF                   = 1
  keyword.TANH                   = 1
  keyword.TASK                   = 1
  keyword.THEN                   = 1
  keyword.THREAD                 = 1
  keyword.THREADID               = 1
  keyword.TIME                   = 1
  keyword.TIMESTAMP              = 1                        /* EP 5.1 */
  keyword.TINY                   = 1
  keyword.TITLE                  = 1
  keyword.TO                     = 1
  keyword.TOTAL                  = 1
  keyword.TPK                    = 1
  keyword.TPM                    = 1
  keyword.TRANSIENT              = 1
  keyword.TRANSLATE              = 1
  keyword.TRANSMIT               = 1
  keyword.TRIM                   = 1
  keyword.TRKOFL                 = 1
  keyword.TRUNC                  = 1
  keyword.TYPE                   = 1
  keyword.UFL                    = 1
  keyword.ULENGTH                = 1                        /* EP 3.8 */
  keyword.ULENGTH16              = 1                        /* EP 3.8 */
  keyword.ULENGTH8               = 1                        /* EP 3.8 */
  keyword.UNAL                   = 1
  keyword.UNALIGNED              = 1
  keyword.UNALLOCATED            = 1
  keyword.UNBUF                  = 1
  keyword.UNBUFFERED             = 1
  keyword.UNDEFINEDFILE          = 1
  keyword.UNDERFLOW              = 1
  keyword.UNDF                   = 1
  keyword.UNLOCK                 = 1
  keyword.UNSIGNED               = 1
  keyword.UNSPEC                 = 1
  keyword.UNTIL                  = 1
  keyword.UPDATE                 = 1
  keyword.UPOS                   = 1                        /* EP 3.8 */
  keyword.UPPERCASE              = 1
  keyword.UPTHRU                 = 1
  keyword.USUBSTR                = 1                        /* EP 3.8 */
  keyword.USUPPLEMENTARY         = 1                        /* EP 4.3 */
  keyword.USURROGATE             = 1                        /* EP 3.9 */
  keyword.UTCDATETIME            = 1                        /* EP 5.1 */
  keyword.UTCSECS                = 1                        /* EP 5.1 */
  keyword.UTF8                   = 1                        /* EP 4.3 */
  keyword.UTF8STG                = 1                        /* EP 5.1 */
  keyword.UTF8TOCHAR             = 1                        /* EP 4.3 */
  keyword.UTF8TOWCHAR            = 1                        /* EP 4.3 */
  keyword.UUID                   = 1                        /* EP 5.1 */
  keyword.UVALID                 = 1                        /* EP 3.8 */
  keyword.UWIDTH                 = 1                        /* EP 3.8 */
  keyword.VALID                  = 1
  keyword.VALIDDATE              = 1
  keyword.VALUE                  = 1
  keyword.VAR                    = 1
  keyword.VARGLIST               = 1
  keyword.VARGSIZE               = 1
  keyword.VARIABLE               = 1
  keyword.VARYING                = 1
  keyword.VARYINGZ               = 1
  keyword.VARYING4               = 1                        /* EP 4.5 */
  keyword.VARZ                   = 1
  keyword.VB                     = 1
  keyword.VBS                    = 1
  keyword.VERIFY                 = 1
  keyword.VERIFYR                = 1
  keyword.VS                     = 1
  keyword.VSAM                   = 1
  keyword.WAIT                   = 1
  keyword.WCHAR                  = 1
  keyword.WCHARVAL               = 1
  keyword.WEEKDAY                = 1
  keyword.WHEN                   = 1
  keyword.WHIGH                  = 1
  keyword.WHILE                  = 1
  keyword.WHITESPACECOLLAPSE     = 1                        /* EP 4.4 */
  keyword.WHITESPACEREPLACE      = 1                        /* EP 4.4 */
  keyword.WIDECHAR               = 1
  keyword.WIDEPIC                = 1                        /* EP 4.4 */
  keyword.WLOW                   = 1
  keyword.WRITE                  = 1
  keyword.XMLCHAR                = 1                        /* EP 3.3 */
  keyword.XMLCLEAN               = 1                        /* EP 4.4 */
  keyword.XMLCONTENT             = 1                        /* EP 5.1 */
  keyword.XPROCEDURE             = 1                        /* EP 4.5 */
  keyword.Y4DATE                 = 1
  keyword.Y4JULIAN               = 1
  keyword.Y4YEAR                 = 1
  keyword.ZDIV                   = 1
  keyword.ZERODIVIDE             = 1
return