aaaaaaaaaaaaaaaaaaaaaa
1234567890 This is a fixed 80 characters width: do not change this text! 4567890
VIEW ehiasm.rex
Command ===> _________________________________________________
******
******
***************************** 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 = '< > & "'
/*********************************************************************
* 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 ****************************