aaaaaaaaaaaaaaaaaaaaaa
1234567890 This is a fixed 80 characters width: do not change this text! 4567890
   File  Edit  Edit_Settings  Menu  Utilities  Compilers  Test  Help
 ———————————————————————————————————————————————————————————————————————————————
 VIEW       ehiasm.rex
 Command ===> _________________________________________________

Columns
00001 00072
Scroll ===> CSR 
 ******
 ******
 
***************************** Top of Data ****************************** /* REXX exec/edit macro to convert ASM to 'HILITE'd HTML */ /*** trace ?r ***************************************************** \| * * (C) Copyright Robert AH Prins, 2007-2009 * ************************************************************************ * ------------------------------------------------------------------ * * | Date | By | Remarks | * * |------------+------+----------------------------------------------| * * | | | | * * |------------+------+----------------------------------------------| * * | 2009-02-09 | RAHP | - Correct comment | * * | | | - 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-17 | RAHP | Complete operand parser | * * |------------+------+----------------------------------------------| * * | 2007-09-11 | RAHP | Initial version (copy of EHIREXX) | * * |------------+------+----------------------------------------------| * ************************************************************************ * EHIASM is a REXX exec/edit macro that analyses ASM 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 and 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 assembler 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 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 ||, 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 /*********************************************************************** * QUOTER: * * * * This procedure adds HTML for quoted strings * ***********************************************************************/ quoter: procedure expose col_str in_apostq parse arg in out = '' if in_apostq then do in_apost = 1 p = pos(' ', in) p = verify(in, ' ',, p) out = left(in, p - 1)col_str in = substr(in, p) end else in_apost = 0 do while in \== '' c = left(in, 1) select when c = '''' &, in_apost then do out = out || '''</em>' in_apost = 0 in_apostq = 0 end when c = '''' &, \in_apost then do out = out || col_str'''' in_apost = 1 in_apostq = 1 end otherwise out = out || c end in = substr(in, 2) end if in_apost then out = out'</em>' return out /*********************************************************************** * HILITE: * * * * This procedure adds HTML for special characters * ***********************************************************************/ hilite: procedure expose special_hilite special_chars special_html, col_spc paren col_par. in_apostq parse arg in out = '' if in_apostq then do in_apost = 1 p = pos(' ', in) p = verify(in, ' ',, p) out = left(in, p - 1) in = substr(in, p) end else in_apost = 0 do while in \== '' c = left(in, 1) select when c = '''' &, in_apost then do out = out || c in_apost = 0 end when c = '''' &, \in_apost then do out = out || c in_apost = 1 end when c = '(' &, \in_apost then do paren = (paren + 1) // 5 out = out || col_par.paren'(</em>' end when c = ')' &, \in_apost then do out = out || col_par.paren')</em>' paren = (paren + 4) // 5 end when pos(c, special_hilite) \= 0 &, \in_apost then do p = wordpos(c, special_chars) if p \= 0 then c = word(special_html, p) out = out || col_spc || c'</em>' end otherwise out = out || c end in = substr(in, 2) end return out /*********************************************************************** * QUOTE_CHECK: * * * * This procedure checks post-keyword data (PARM=) for quotes * ***********************************************************************/ quote_check: procedure expose l2 l3 t2 = l2 t3 = l3 q2 = space(t2, 0) z2 = space(translate(t2, ' ', ''''), 0) /********************************************************************* * If d = 1 there are unmatched quotes * *********************************************************************/ d = (length(q2) - length(z2)) // 2 do while d = 1 & t3 \= ' ' p = pos('''', t3) t2 = t2 || left(t3, p) t3 = substr(t3, p + 1) do while left(t3, 1) \= ' ' t2 = t2 || left(t3, 1) t3 = substr(t3, 2) end q2 = space(t2, 0) z2 = space(translate(t2, ' ', ''''), 0) d = (length(q2) - length(z2)) // 2 end l2 = t2 l3 = t3 return /*********************************************************************** * GET_SOURCE: * * * * Read the assembler source * ***********************************************************************/ get_source: macmode = 0 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 /***************************************************************** * Read the (selected) source into a stem * *****************************************************************/ i = 0 do j = +zf to +zl "isredit (DATALINE) = line" j i = i + 1 rxdata.i = strip(dataline, 'T') end rxdata.0 = i 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.asm.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 assembler source * *****************************************************************/ 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 "( stem rxdata. finis" if rc > 0 then do say 'Error - Dataset' idsn 'could not be read - rc' rc exit 8 end "free f("dynlib")" end olines = rxdata.0 return /*********************************************************************** * GET_SOURCE_PC: * * * * Read the text when running on the PC * ***********************************************************************/ get_source_pc: if idsn = '' then do say 'Syntax:' moi 'file.asm' exit end do i = 1 by 1 while lines(idsn) rxdata.i = linein(idsn) 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, 'ннннн', ' <>&"') /********************************************************************* * 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), html_ext (sep) . /********************************************************************* * Temporary output dataset * *********************************************************************/ if mem \= '' then odsn = "'" || userid() || '.' || mem || ".asm."html_ext"'" else odsn = "'" || userid() || '.' || moi || ".asm."html_ext"'" /********************************************************************* * Text strings for title, header and footer * *********************************************************************/ title = 'Assembler source:' strip(idsn,, '''') header = 'Assembler 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_ext else htmlfile = 'asm.'html_ext /********************************************************************* * HTML colors * *********************************************************************/ col_nam = '<em class="ispflime">' /* lime(green) - name */ col_opc = '<em class="ispfred">' /* red - opcode */ col_opr = '<em class="ispflime">' /* lime - operand */ col_str = '<em class="ispfwhite">' /* white - strings */ col_rem = '<em class="ispfturq">' /* aqua(turq) - remarks */ col_spc = '<em class="ispfyellow">'/* yellow - special characters */ col_pro = '<em class="ispfblue">' /* blue - *process */ /********************************************************************* * Colors for nested parentheses * *********************************************************************/ col_par.0 = '<em class="ispffuchsia">' col_par.1 = '<em class="ispfyellow">' col_par.2 = '<em class="ispfwhite">' col_par.3 = '<em class="ispfred">' col_par.4 = '<em class="ispfturq">' /********************************************************************* * HTML special characters and their defined entities * *********************************************************************/ special_chars = '< > & "' special_html = '&lt; &gt; &amp; &quot;' /********************************************************************* * Characters to be highlighted * *********************************************************************/ special_hilite = '+-*/=<>&^|:,' /********************************************************************* * No operand (pseudo-) instructions * *********************************************************************/ no_ops = 'CSCH ' ||, 'HSCH ' ||, 'IPK ' ||, 'PTFF ' ||, 'PTLB ' ||, 'RCHP ' ||, 'RSCH ' ||, 'SAL ' ||, 'SAM ' ||, 'SAM24 ' ||, 'SAM31 ' ||, 'SAM64 ' ||, 'SCHM ' ||, 'SCKPF ' ||, 'TAM ' ||, 'TRAP2 ' ||, 'UPT ' ||, 'XSCH ' ||, 'AEJECT ' ||, 'ANOP ' ||, 'COM ' ||, 'CSECT ' ||, 'CXD ' ||, 'DSECT ' ||, 'EJECT ' ||, 'LTORG ' ||, 'MACRO ' ||, 'MEND ' ||, 'MEXIT ' ||, 'REPRO ' ||, 'RSECT ' return /*********************************************************************** * BUILD_HTML: * * * * This procedure builds the HTML output * ***********************************************************************/ build_html: /********************************************************************* * Switches * *********************************************************************/ in_apost = 0 /* Inside a '(apost) delimited string */ in_apostq = 0 /* Inside a '(apost) delimited string */ in_com = 0 /* Inside a comment */ paren = 1 /* Nested parentheses level */ /********************************************************************* * Initialize the html output string * *********************************************************************/ if ispf_edit \= 'NONE' then htmlout = x2c(ff)ispf_edit || x2c(ff)right(olines, 6, '0')x2c(ff) else htmlout = '' tempout = '' /********************************************************************* * Loop over the assembler source * *********************************************************************/ i = time('E') /********************************************************************* * Process (if present) any '*PROCESS' statements * *********************************************************************/ do i = 1 by 1 while translate(left(rxdata.i, 8)) = '*PROCESS' tempout = tempout || col_pro ||, translate_entities(rxdata.i)'</em><br>' end do i = i to rxdata.0 /******************************************************************* * Display (optional) progress messages * *******************************************************************/ if show_progress > 0 then if i // show_progress = 0 then say 'Elapsed time' right(time('E'), 12), '- lines processed' right(i, 6) /******************************************************************* * Get the line, a spaced copy and the continuation character * *******************************************************************/ line = left(rxdata.i, 71) sqz = space(line) cont = substr(rxdata.i, 72, 1) if cont == ' ' then line = strip(left(rxdata.i, 71), 'T') /******************************************************************* * Process completely blank line * *******************************************************************/ if sqz = '' then do tempout = tempout || '<br>' iterate i end /******************************************************************* * Process comment line * *******************************************************************/ if in_com |, left(line, 1) = '*' |, left(line, 2) = '.*' then do if cont \= '' then in_com = 1 else in_com = 0 tempout = tempout || col_rem ||, translate_entities(line) || '</em><br>' iterate i end /******************************************************************* * Parse out the name (and following spaces) * * * * As there may not always be a name present, a '~' is added to the * * line, so that there is in effect always a name. The '~' is later * * stripped off again. * *******************************************************************/ line = '~'line p = pos(' ', line) name = substr(left(line, p - 1), 2) line = substr(line, p) p = verify(line, ' ') if p \= 0 then do name = name || left(line, p - 1) line = substr(line, p) end if name \= '' then tempout = tempout || col_nam || name || '</em>' else tempout = tempout || name /******************************************************************* * Parse out the opcode (and following spaces) * *******************************************************************/ p = pos(' ', line || ' ') opcode = left(line, p - 1) upcode = translate(opcode) line = substr(line, p) p = verify(line, ' ') if p \= 0 then do opcode = opcode || left(line, p - 1) line = substr(line, p) end else if line = ' ' &, cont \= ' ' then do opcode = opcode || line line = '' end tempout = tempout || col_opc || opcode || '</em>' /******************************************************************* * If followed by '(', these 'opcodes' allow non-breaking spaces in * * their operand field * *******************************************************************/ spc = (upcode = 'AIF' |, upcode = 'SETA' |, upcode = 'SETB' |, upcode = 'SETC') & left(line, 1) = '(' /******************************************************************* * 'no_ops' contains the list of non-operand opcodes and assembler * * instructions * *******************************************************************/ no_op = (wordpos(upcode, no_ops) \= 0) /******************************************************************* * Remainder of line is blank and no continuation? Exit * *******************************************************************/ if line \= '' |, cont \= ' ' then call parser tempout = tempout || '<br>' if length(tempout) > 250 then do htmlout = htmlout || tempout tempout = '' end end htmlout = htmlout || tempout return /*********************************************************************** * PARSER: * * * * Parse the operand and remainder fields * ***********************************************************************/ parser: in_apost = 0 par_cnt = -1 in_sym = 0 do while line \= '' | cont \= ' ' if line == '' &, cont \= ' ' then do tempout = tempout || col_rem || cont || '</em><br>' i = i + 1 line = left(rxdata.i, 71) cont = substr(rxdata.i, 72, 1) if cont = ' ' then line = strip(line, 'T') /*************************************************************** * Assume valid code, so continuations start in column 16 * ***************************************************************/ tempout = tempout || left(line, 15) line = substr(line, 16) end do while line \== '' c1 = left(line, 1) u1 = translate(c1) c2 = left(line, 2) u2 = translate(c2) /***************************************************************** * Is it a special character? * *****************************************************************/ sc = wordpos(c1, special_chars) /***************************************************************** * Is it a special hilite character? * *****************************************************************/ sh = pos(c1, special_hilite) if in_sym &, pos(u1, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_#@') = 0 then in_sym = 0 if c1 = '&' then in_sym = 1 select /*************************************************************** * Everything following a no-operand opcode or assembler * * instruction is a comment * ***************************************************************/ when no_op then do tempout = tempout || col_rem || line'</em>' line = '' end /*************************************************************** * Spaces are kept unchanged - process multiple spaces in one * * go| * ***************************************************************/ when c1 == ' ' then do if line = ' ' then do tempout = tempout || line line = '' end else do n = verify(line, ' ') tempout = tempout || left(line, n - 1) if in_apost then line = substr(line, n) else if spc then if par_cnt = 0 then do tempout = tempout ||, col_rem || substr(line, n)'</em>' line = '' end else line = substr(line, n) else do tempout = tempout ||, col_rem || substr(line, n) || '</em>' line = '' end end end /*************************************************************** * Start of quoted operator * ***************************************************************/ when \in_sym &, \in_apost &, (u2 = 'L''' |, u2 = 'L''' |, u2 = 'K''' |, u2 = 'D''' |, u2 = 'I''' |, u2 = 'N''' |, u2 = 'O''' |, u2 = 'S''' |, u2 = 'T''') then do tempout = tempout || c2 line = substr(line, 3) end /*************************************************************** * End of quoted string * ***************************************************************/ when in_apost &, c1 = "'" then do in_apost = 0 tempout = tempout || "'</em>" line = substr(line, 2) end /*************************************************************** * Start of quoted string * ***************************************************************/ when c1 = "'" then do in_apost = 1 tempout = tempout || col_str"'" line = substr(line, 2) end /*************************************************************** * A special character has to be translated and highlighted * ***************************************************************/ when sc > 0 &, sh > 0 &, \in_apost then do tempout = tempout || col_spc ||, word(special_html, sc)'</em>' line = substr(line, 2) end /*************************************************************** * A special character has to be translated * ***************************************************************/ when sc > 0 then do tempout = tempout || word(special_html, sc) line = substr(line, 2) end /*************************************************************** * A special character has to be highlighted * ***************************************************************/ when sh > 0 &, \in_apost then do tempout = tempout || col_spc || c1'</em>' line = substr(line, 2) end /*************************************************************** * It's a left parenthesis * ***************************************************************/ when c1 = '(' &, \in_apost then do if par_cnt = -1 then par_cnt = 1 else par_cnt = par_cnt + 1 paren = (paren + 1) // 5 tempout = tempout || col_par.paren'(</em>' line = substr(line, 2) end /*************************************************************** * It's a right parenthesis * ***************************************************************/ when c1 = ')' &, \in_apost then do par_cnt = par_cnt - 1 tempout = tempout || col_par.paren')</em>' paren = (paren + 4) // 5 line = substr(line, 2) end /*************************************************************** * Anything else * ***************************************************************/ otherwise do tempout = tempout || c1 line = substr(line, 2) end end if length(tempout) > 250 then do htmlout = htmlout || tempout tempout = '' end end end return **************************** Bottom of Data ****************************