To support this I would like to briefly give some glimpse at a tool that I have been developing, but
because of my current time restrictions has not been proceeded to the stage where I would be able to
hand it out to the public, but which could be used to easily analyze and exploit "label annotations"
as discussed in this thread [thinking of this it would be very helpful when debugging programs and
analyzing certain code segments using labels to become able to see e.g. which statements get
executed (and which not) under which conditions].
The tool is currently named "tracetool" and takes advantage of the new TraceObject class. One
intended application is to run any Rexx and ooRexx programs in trace mode, intercept the trace and
store it as a trace log in a file for inspection and analysis. In case problems occur the trace log
could be sent to the authors of the Rexx or ooRexx program for analysis.
In this application having the ability to place labels in programs the value of an analysis with
"trace labels" would be enhanced considerably! The trace logs could be analyzed manually or by Rexx
or ooRexx programs quite easily. (The tool as it is stands now is already able to analyze a trace
log to find the deadlocked parts of an ooRexx program and mark all places that are deadlocked and
all places where a wait on a guard lock takes place. This has only become possible because of the
powerful trace keyword instruction in combination with the TraceObject class.)
To give a little example, here a Rexx program that gets run without and with
"::options trace labels".
The program:
parse source op_sys +1 . . s fileName=filespec("n",s) say "ob_sys:" op_sys
"fileName:" fileName
if op_sys='W' then do if random(0,1) then signal win else signal other end
else do if
random(0,1) then signal other else signal win end win: call winInfo fileName
signal continue
other: call otherInfo fileName continue: say "done." exit winInfo: procedure
parse arg fileName
say .context~name"|winInfo:" fileName return ::routine otherInfo parse arg
fileName say
.context~name"|otherInfo:" fileName
Running it a couple of times (to get random() to use both branches) without
trace yields one of:
G:\test\orx\trace\testLabel>testLabel.rex
ob_sys: W fileName: testLabel.rex
WININFO|winInfo: testLabel.rex
done.
...
G:\test\orx\trace\testLabel>testLabel.rex
ob_sys: W fileName: testLabel.rex
OTHERINFO|otherInfo: testLabel.rex
done.
Running the same program adding "::options trace label" at the end a couple of times (to get
random() to use both branches) yields one of:
--- with "::options trace labels"
G:\test\orx\trace\testLabel>testLabel.rex
ob_sys: W fileName: testLabel.rex
19 *-* win:
29 *-* winInfo:
WININFO|winInfo: testLabel.rex
25 *-* continue:
done.
...
G:\test\orx\trace\testLabel>testLabel.rex
ob_sys: W fileName: testLabel.rex
22 *-* other:
>I> Routine "OTHERINFO" in package
"G:\test\orx\trace\testLabel\testLabel.rex".
OTHERINFO|otherInfo: testLabel.rex
<I< Routine "OTHERINFO" in package
"G:\test\orx\trace\testLabel\testLabel.rex".
25 *-* continue:
done.
So "trace label" shows each encountered label which differs in this example depending on the
random(0,1) function value generated.
Using the original program (without an "::options trace labels" in it) the tool allows for running
it with different trace options in effect, including "trace label", here an example ("-tl" means
"trace labels"):
G:\test\orx\trace\testLabel>tracetool -tl testLabel.rex
The output in the terminal may be:
ob_sys: W fileName: testLabel.rex
WININFO|winInfo: testLabel.rex
done.
By default the trace log's file name will be in this case: "testLabel.rex_trace.xml" which we can
feed to the tracetool to display the trace lines like this:
G:\test\orx\trace\testLabel>tracetool -s testLabel.rex_trace.xml
>I> Routine "testLabel.rex" in package "testLabel.rex".
19 *-* win:
29 *-* winInfo:
25 *-* continue:
<I< Routine "testLabel.rex" in package "testLabel.rex".
If one wishes to get almost all trace information (which in this case is not
really needed):
G:\test\orx\trace\testLabel>tracetool -s -fm1 testLabel.rex_trace.xml
# 1 | 15:46:31.443000 [R1 T2 I1 ] >I> Routine
"testLabel.rex" in package "testLabel.rex".
# 2 | 15:46:31.444000 [R1 T2 I1 ] 19 *-* win:
# 3 | 15:46:31.444000 [R1 T2 I2 ] 29 *-*
winInfo:
# 4 | 15:46:31.445000 [R1 T2 I1 ] 25 *-*
continue:
# 5 | 15:46:31.445000 [R1 T2 I1 ] <I< Routine
"testLabel.rex" in package "testLabel.rex".
The created trace log will be by default xml encoded and will look like this (and could be analyzed
by applying XSLT scripts or Rexx scripts etc.):
<traceLog> <traceObject> <option>P</option> <number>1</number>
<timestamp>2024-11-11T15:46:31.443000</timestamp>
<interpreter>1</interpreter>
<thread>2</thread> <invocation>1</invocation> <lineNr>1</lineNr>
<callerStackFrame>
<arguments></arguments> <executableId>FD17BD87</executableId>
<executablePackage>REXX</executablePackage> <line>.nil</line>
<name>CALL</name>
<package>REXX</package> <scope>Routine</scope> <scopeId>FD17C3AB</scopeId>
<scopePackage>REXX</scopePackage> <target>a Routine</target>
<targetCanonicalName>a
Routine</targetCanonicalName> <targetId>FB4680AF</targetId>
<targetPackage>REXX</targetPackage>
<targetPackageId>FD219897</targetPackageId> <traceLine> *-* Compiled method
"CALL" with scope
"Routine".</traceLine> <type>METHOD</type> </callerStackFrame> <stackFrame>
<arguments></arguments> <executableId>FB4680AF</executableId>
<executablePackage>testLabel.rex</executablePackage> <line>1</line>
<name>testLabel.rex</name>
<package>testLabel.rex</package> <target>.nil</target> <traceLine> 1 *-*
parse source op_sys +1
. . s</traceLine> <type>ROUTINE</type> </stackFrame> <traceLine> >I>
Routine
"testLabel.rex" in package "testLabel.rex".</traceLine> </traceObject>
<traceObject>
<option>P</option> <number>2</number>
<timestamp>2024-11-11T15:46:31.444000</timestamp>
<interpreter>1</interpreter> <thread>2</thread> <invocation>1</invocation>
<lineNr>19</lineNr>
<stackFrame> <arguments></arguments> <executableId>FB4680AF</executableId>
<executablePackage>testLabel.rex</executablePackage> <line>19</line>
<name>testLabel.rex</name>
<package>testLabel.rex</package> <target>.nil</target> <traceLine> 19 *-*
win:</traceLine>
<type>ROUTINE</type> </stackFrame> <traceLine> 19 *-* win:</traceLine>
</traceObject>
<traceObject> <option>P</option> <number>3</number>
<timestamp>2024-11-11T15:46:31.444000</timestamp>
<interpreter>1</interpreter>
<thread>2</thread> <invocation>2</invocation> <lineNr>29</lineNr>
<stackFrame>
<arguments>testLabel.rex</arguments> <executableId>FB4680AF</executableId>
<executablePackage>testLabel.rex</executablePackage> <line>29</line>
<name>WININFO</name>
<package>testLabel.rex</package> <target>.nil</target> <traceLine> 29 *-*
winInfo:</traceLine>
<type>INTERNALCALL</type> </stackFrame> <traceLine> 29 *-* winInfo:</traceLine>
</traceObject>
<traceObject> <option>P</option> <number>4</number>
<timestamp>2024-11-11T15:46:31.445000</timestamp>
<interpreter>1</interpreter>
<thread>2</thread> <invocation>1</invocation> <lineNr>25</lineNr>
<stackFrame>
<arguments></arguments> <executableId>FB4680AF</executableId>
<executablePackage>testLabel.rex</executablePackage> <line>25</line>
<name>testLabel.rex</name>
<package>testLabel.rex</package> <target>.nil</target> <traceLine> 25 *-*
continue:</traceLine>
<type>ROUTINE</type> </stackFrame> <traceLine> 25 *-* continue:</traceLine>
</traceObject>
<traceObject> <option>P</option> <number>5</number>
<timestamp>2024-11-11T15:46:31.445000</timestamp>
<interpreter>1</interpreter>
<thread>2</thread> <invocation>1</invocation> <lineNr>27</lineNr>
<stackFrame>
<arguments></arguments> <executableId>FB4680AF</executableId>
<executablePackage>testLabel.rex</executablePackage> <line>27</line>
<name>testLabel.rex</name>
<package>testLabel.rex</package> <target>.nil</target> <traceLine> 27 *-*
exit</traceLine>
<type>ROUTINE</type> </stackFrame> <traceLine> <I< Routine
"testLabel.rex" in package
"testLabel.rex".</traceLine> </traceObject> </traceLog>
The tool allows to create the logfile in json encoded format instead, e.g.
[ { "option": "P", "number": 1, "timestamp": "2024-11-11T15:46:31.443000",
"interpreter": 1,
"thread": 2, "invocation": 1, "lineNr": 1, "callerStackFrame": { "arguments":
"",
"executableId": "FD17BD87", "executablePackage": "REXX", "line": null, "name":
"CALL",
"package": "REXX", "scope": "Routine", "scopeId": "FD17C3AB", "scopePackage": "REXX",
"target":
"a Routine", "targetCanonicalName": "a Routine", "targetId": "FB4680AF",
"targetPackage":
"REXX", "targetPackageId": "FD219897", "traceLine": " *-* Compiled method
\"CALL\"with scope
\"Routine\".", "type": "METHOD" }, "stackFrame": { "arguments": "", "executableId":
"FB4680AF",
"executablePackage": "testLabel.rex", "line": "1", "name": "testLabel.rex",
"package":
"testLabel.rex", "target": null, "traceLine": " 1 *-* parse source op_sys +1 . . s",
"type":
"ROUTINE" }, "traceLine": " >I> Routine \"testLabel.rex\"in package
\"testLabel.rex\"." }, {
"option": "P", "number": 2, "timestamp": "2024-11-11T15:46:31.444000",
"interpreter": 1,
"thread": 2, "invocation": 1, "lineNr": 19, "stackFrame": { "arguments": "",
"executableId":
"FB4680AF", "executablePackage": "testLabel.rex", "line": "19", "name":
"testLabel.rex",
"package": "testLabel.rex", "target": null, "traceLine": " 19 *-* win:", "type":
"ROUTINE" },
"traceLine": " 19 *-* win:" }, { "option": "P", "number": 3, "timestamp":
"2024-11-11T15:46:31.444000", "interpreter": 1, "thread": 2, "invocation": 2,
"lineNr": 29,
"stackFrame": { "arguments": "testLabel.rex", "executableId": "FB4680AF",
"executablePackage":
"testLabel.rex", "line": "29", "name": "WININFO", "package": "testLabel.rex",
"target": null,
"traceLine": " 29 *-* winInfo:", "type": "INTERNALCALL" }, "traceLine": " 29 *-*
winInfo:" }, {
"option": "P", "number": 4, "timestamp": "2024-11-11T15:46:31.445000",
"interpreter": 1,
"thread": 2, "invocation": 1, "lineNr": 25, "stackFrame": { "arguments": "",
"executableId":
"FB4680AF", "executablePackage": "testLabel.rex", "line": "25", "name":
"testLabel.rex",
"package": "testLabel.rex", "target": null, "traceLine": " 25 *-* continue:", "type":
"ROUTINE"
}, "traceLine": " 25 *-* continue:" }, { "option": "P", "number": 5,
"timestamp":
"2024-11-11T15:46:31.445000", "interpreter": 1, "thread": 2, "invocation": 1,
"lineNr": 27,
"stackFrame": { "arguments": "", "executableId": "FB4680AF",
"executablePackage":
"testLabel.rex", "line": "27", "name": "testLabel.rex", "package": "testLabel.rex",
"target":
null, "traceLine": " 27 *-* exit", "type": "ROUTINE" }, "traceLine": " <I<
Routine
\"testLabel.rex\"in package \"testLabel.rex\"." } ]
or as a csv-file with a header line, e.g.
option,number,timestamp,interpreter,thread,invocation,lineNr,callerStackFrame,stackFrame,variable,receiver,receiverCanonicalName,receiverId,attributePool,scopeLockCount,isGuarded,hasScopeLock,isWaiting,isBlocked,traceLine
"P","1","2024-11-11T15:46:31.443000","1","2","1","1","arguments: /
executableId: FD17BD87 /
executablePackage: REXX / line: .nil / name: CALL / package: REXX / scope:
Routine / scopeId:
FD17C3AB / scopePackage: REXX / target: a Routine / targetCanonicalName: a
Routine / targetId:
FB4680AF / targetPackage: REXX / targetPackageId: FD219897 / traceLine: *-*
Compiled method
""CALL"" with scope ""Routine"". / type: METHOD / ","arguments: /
executableId: FB4680AF /
executablePackage: testLabel.rex / line: 1 / name: testLabel.rex / package:
testLabel.rex /
target: .nil / traceLine: 1 *-* parse source op_sys +1 . . s / type: ROUTINE /
",,,,,,,,,,," >I>
Routine ""testLabel.rex"" in package ""testLabel.rex""."
"P","2","2024-11-11T15:46:31.444000","1","2","1","19",,"arguments: /
executableId: FB4680AF /
executablePackage: testLabel.rex / line: 19 / name: testLabel.rex / package:
testLabel.rex /
target: .nil / traceLine: 19 *-* win: / type: ROUTINE / ",,,,,,,,,,," 19 *-*
win:"
"P","3","2024-11-11T15:46:31.444000","1","2","2","29",,"arguments:
testLabel.rex / executableId:
FB4680AF / executablePackage: testLabel.rex / line: 29 / name: WININFO /
package: testLabel.rex
/ target: .nil / traceLine: 29 *-* winInfo: / type: INTERNALCALL /
",,,,,,,,,,," 29 *-*
winInfo:" "P","4","2024-11-11T15:46:31.445000","1","2","1","25",,"arguments:
/ executableId:
FB4680AF / executablePackage: testLabel.rex / line: 25 / name: testLabel.rex
/ package:
testLabel.rex / target: .nil / traceLine: 25 *-* continue: / type: ROUTINE /
",,,,,,,,,,," 25
*-* continue:"
"P","5","2024-11-11T15:46:31.445000","1","2","1","27",,"arguments: /
executableId: FB4680AF / executablePackage: testLabel.rex / line: 27 / name:
testLabel.rex /
package: testLabel.rex / target: .nil / traceLine: 27 *-* exit / type: ROUTINE /
",,,,,,,,,,,"
<I< Routine ""testLabel.rex"" in package ""testLabel.rex""."
As you can see there is a lot of trace information made available in trace logs by tracetool in
different encodings meant to allow anyone who has a need to analyze trace logs to do so.
Now, if it was possible in ooRexx to fully label all kind of areas/statements together with a tool
like tracetool makes it possible to create programs that can quickly analyze and produce any kind of
report, allowing one to even analyze the most complex Rexx programs.
---
So, whoever has a little time and has the knowledge to quickly adjust the ooRexx label keyword
statement to allow for full labeling, please do so!
It would be much appreciated and a very helpful addition for Rexx programmers to debug Rexx or
ooRexx programs.
---rony
On 25.10.2024 22:29, Rick McGuire wrote:
On Fri, Oct 25, 2024 at 4:24 PM Chip Davis <c...@aresti.com> wrote:
And yet, Rick said, "So the question comes down to 1) disallow them if they
appear in a
location where they can't be branched to, or 2) allow them, but catch all
attempts to branch
to one in a bad location. From my standpoint, catching them at translation
time and raising an
error is much better than the disruption that would be caused to rework the
internals to raise
an error at run time. And the nice thing about raising an error up front is
that it is always
easier to lift a restriction later than try to impose one after the fact."
"... the attempt to branch to them" is at execution time, and Rick has
already deemed it a
"disruption that would be caused to rework the internals to raise an error at
run time", so
that seems like a heavy lift to me.
I took a quick look at the code, the disruption is much less severe that I first thought and can
even be done without causing problems with programs saved using rexxc.
Rick
I still agree with JMB's "take". "Belling the cat" at run-time sounds like
a non-trivial effort.
-Chip-
On 10/25/2024 9:35 AM, Gilbert Barmwater wrote:
I've read all the comments (so far) on this and the ones that had the most
impact on my
opinion were Mike's -
"...it's the attempt to branch to them that should be flagged, not the
label itself, which is
just a label." - and Jeremy's - "Some users might be running code that they
don't have source
for - ie they've been supplied with the output from rexxc. Why should they
not be able to
continue to run their programs?". So I vote for allowing "trace only"
labels but raising an
error if an attempt is made to SIGNAL or CALL them.
On 10/23/2024 9:31 AM, Josep Maria Blasco wrote:
Hi all,
There are some ongoing changes to the ooRexx interpreter that will strongly
affect the
language definition, in such a way that the 5.1.0 release may end up
implementing a version
of the language that does no longer allow us to hold true what is asserted
in the landing
page for the project:
"Home of the Open Object Rexx Project. ooRexx is the open source
version of IBM's Object
REXX Interpreter. *It is upwardly compatible with classic REXX and will
execute classic
REXX programs unchanged*. The project is managed by the Rexx Language
Association".
In the preceding paragraph, I have highlighted the part that will become
problematic if the
ongoing changes consolidate. Namely,
* Any program containing labels inside block instructions will
immediately stop working
(with syntax error 47.002 for DO/LOOP, 47.003 for IF, and 47.004 for
SELECT).
* Any program containing labels before the initial EXPOSE or USE LOCAL
method instructions
will fail (with 99.910 for USE LOCAL and 99.907 for EXPOSE).
Please note that _these programs will stop working even if they never
branch_ (i.e., SIGNAL
or CALL) _to any of these labels_. Normal ("classic Rexx") semantics for
such labels is to
treat them as null clauses, except for tracing purposes: when TRACE Labels
is in effect, the
language processor
Traces [...] labels passed during program execution. This is especially
useful
with debug mode, when the language processor pauses after each
invocation or call
(rexxref 2.29.1).
If the ongoing changes consolidate into the 5.1.0 release, our claim of
compatibility with
classic Rexx will no longer be valid.
My impression is that these changes should be reverted, but I understand
that there has been
a considerable amount of effort put by the developers in implementing these
modifications,
and therefore such a reversal should not be undertaken slightly.
Please allow me to elaborate on the background behind these changes, to
widen our
perspective about the subject.
*Statement of the problem*
A label is a clause. Following TRL2 (and TRL1, in that respect), "more than
one label may
precede /any instruction/" (emphasis mine). Some interpreters seem to allow
labels preceding
/any clause/. To appreciate the difference between the two concepts, please
consider the
following small program:
Trace L
A: If 1 = 1
B: Then
C: Say "Hi"
Object Rexx (6.00, ArcaOS) chokes on B:, but allows A: and C: (THEN is not
an instruction by
itself); Regina Rexx happily processes A:, B: and C: (and traces them, when
asked); the
current version of ooRexx refuses to run the above program, even if we
eliminate the B:
label (it produces a 47.3, 'Labels are not allowed within an IF block; found
"C"').
The ANSI standard defines labels inside a block instruction as
"trace-only", and reserves
errors 16.2 and 16.3 for the cases when a CALL or SIGNAL instruction tries
to target one of
these labels.
The Errata for the Rexx standard explicitly corrects 6.3.2.14 and 6.3.2.19,
stating "This
disallows labels before the THEN keyword".
Now the question is the following:
*
*
*¿What variant of the language should ooRexx implement?*
There was some discussion in the developers list (starting at
https://sourceforge.net/p/oorexx/mailman/message/58813104/) about whether
labels inside
block instructions should be allowed to be called/branched to. The
consensus was that this
should not be allowed, putting ooRexx in line with the ANSI standard in
this respect. I
agree with that.
There was also a discussion about whether labels should be allowed when/
they cannot be
branched to/. The example used was relatively ambiguous, since it used a
label before a THEN
keyword:
label: THEN
¿Why do I say that this is an ambiguous example? Because one might object
to disallowing
such a label, a) because THEN is not an instruction, or b) because THEN is
part of an IF.
Depending on how we understand the example, we will have two different
versions of the language.
*The main point is this*
One may have good reasons to want to disallow labels before THEN and, at
the same time,
think that /instructions/ inside other instructions (i.e., /not/ clauses
which are not
instructions by themselves) deserve to have labels, even if they are, as
the ANSI standard
says, trace-only.
*My take is the following*
Labels before THEN, ELSE, WHEN, OTHERWISE or END should not be allowed. All
other labels
should be allowed, including before EXPOSE and USE LOCAL. SIGNALing or
CALLing a label
before EXPOSE or USE LOCAL, or a label inside an IF/DO/LOOP/SELECT should
produce an error.
*What do you all think?*
This is important. We are about to change the definition of the language,
making it
potentially incompatible with many existing programs.
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel