Gforth, FORGET and LIST words as in the original Forth - forth

Is there an equivalent to forget word of Forth in Gforth?
I've seen about marker, but it doesn't have the same behaviour. Also the list command doesn't seem to give a listing of the program.
I'd like to view a list of the in-memory program, just like old list in BASIC - I think that was the behaviour in the original Forth also.

FORGET is obsolescent and is included as a concession to existing implementations according to the Forth standard and the word you need to "list" a Forth word is SEE <word>.
This word is obsolescent and is included as a concession to existing
implementations.
forth-standard.org/standard/tools/FORGET

I don't know Gforth, but FORGET based on an old FIG Forth listing is shown below. It is very sensitive to the dictionary layout and vocabulary organisation. Words like nfa (name field address) and lfa (link field address ) have more modern equivalents. This crashed (VFX) Forth when I ran it, but it may point somebody in the right direction.
variable FENCE
\ Per fig forth listing ( slightly modernised )
: forget \ "word-to-forget-from"
CURRENT # CONTEXT # - ABORT" Vocabulary error."
' DUP FENCE # < ABORT" Word below FENCE."
DUP NFA DP ! LFA # CURRENT ! ;
DP # FENCE !
\ What was tested. WARNING crashed Forth!!
\ My guess is that CURRENT needs to be set to a different address
: forget \ "word-to-forget-from"
CURRENT # CONTEXT # - ABORT" Vocabulary error."
' DUP FENCE # < ABORT" Word below FENCE."
>LINK DUP DP ! \ Set the top of the dictionary
# CURRENT ! ; \ Point current to the last valid definition
There may be ways to leverage the implementation of marker. It must store a restore pointer which may be accessible to be reset to the relevant address of some definition.

It seems to me like MARKER does the same thing as FORGET. The only difference is that you need to set it up in advance. I can confirm the behavior is as stated in Starting Forth [1] with Gforth 0.7.3. Here is the excerpt:
The word FORGET looks up a given word in the dictionary and, in
effect, removes it from the dictionary along with anything you may
have defined since that word. FORGET, like the interpreter, searches
starting from the back; he only removes the most recently defined
versions of the word (along with any words that follow). So now when
you type GREET at the terminal, the interpreter finds the original
GREET.
FORGET is a good word to know; he helps you to weed out your
dictionary so it won’t overflow. (The dictionary takes up memory
space, so as with any other use of memory, you want to conserve it.)
Some Forths do not have FORGET. In that case you need to plan the
forgetting in advance, e.g.:
MARKER -work
defines the null definition -work to mark the current system state for
you. When you execute -work at some later time, the system state is
restored to that in effect when -work was defined. In particular, all
words defined after the marker word -work are completely removed from
the dictionary.
[1] https://www.forth.com/starting-forth/3-forth-editor-blocks-buffer/

Related

How do you quit a Forth environment?

If I am in a Forth environment, how do I leave, and how do I program a word to leave?
There are two ways to 'leave' Forth code, depending on what you need to do.
BYE
The Forth standard defines the word BYE to leave the Forth environment itself.
BYE ( -- )
Return control to the host operating system, if any.
This word gets a lot of creative interpretations when your Forth is not running as a program in an operating system. For example, on some systems where Forth is the operating system, BYE causes the system to restart instead, letting you load another OS.
BYE is part of the Programming-Tools Extensions word set.
QUIT
There is a word in the Core word set called QUIT, but it does not leave the environment. Instead, it leaves execution of a word and returns you back to the interpreter. This is why it is called 'QUIT', it is quitting in another sense.
QUIT ( -- ) ( R: i*x -- )
Empty the return stack, store zero in SOURCE-ID if it is present, make user input device the input source, and enter interpretation state. Do not display a message. Repeat the following:
Accept a line from the input source into the input buffer, set >IN to zero, and interpret.
Display the implementation-defined system prompt if in interpretation state, all processing has been completed, and no ambiguous condition exists.
Rather than defining QUIT as something like "this word returns you to the interpreter", instead QUIT is really defined as the interpreter itself in the Forth standard. In a factored Forth implementation, this makes sense: the word that puts you back in the interpreter and the interpreter itself can be the same word, they both can just clear the return stack and start interpreting.
And QUIT is the word you are more likely to see used in colon definitions, because it is a convenient way to break out of a stack of word executions, leaving the current contents of the data stack as-is, and returning to the interpreter. You can, of course, use BYE in a colon definition, for example in a custom interpreter or environment written in Forth to exit back to the operating system.

Why does Forth reserve two cells per variable?

While trying to find out how Forth manages the dictionary (and memory in general), I came across this page. Being familiar with C, I have no problem with the concept of pointers, and I assume I understood everything correctly. However, at the end of the page are several exercises, and here I noticed something strange.
Exercise 9.4, assuming DATE has been defined as a VARIABLE, asks what the difference is between
DATE .
and
' DATE .
and exercise 9.5 does the same using the user variable BASE.
According to the supplied answers, both phrases will give the same result (also with BASE). Trying this with Win32Forth however, gives results with a difference of 4 bytes (1 cell). Here is what I did:
here . 4494668 ok
variable x ok
x . 4494672 ok
' x . 4494668 ok
Creating another variable gives a similar result:
variable y ok
y . 4494680 ok
' y . 4494676 ok
Thus, it looks like each variable gets not just one cell (for the value), but two cells. The variable itself points to where the actual value is stored, and retrieving the contents at the execution token (using ' x ?) gives 0040101F for both variables.
For exercise 9.5, my results are:
base . 195F90 ok
' base . 40B418 ok
These are not even close to each other. The answer for this exercise does however mention that the results can depend on how BASE is defined.
Returning to normal variables, my main question thus is: why are two cells reserved per variable?
Additionally:
Since only one cell contains the actual value, what do the contents of the other cell mean?
Is this specific to Win32Forth? What happens in other implementations?
Is this different for run-time and compile-time variables?
How do answers to the above questions apply to user variables (such as BASE)?
EDIT1: Okay, so Forth also stores a header for each variable, and using the ' gives you the address of this header. From my tests I would then conclude the header uses just one cell, which does not correspond to all the information the header should contain. Secondly, according to the exercise retrieving the address of a variable should for both cases give the same result, which appears to contradict the existence of a header altogether.
My gut feeling is that this is all very implementation-specific. If so, what happens in Win32Forth, and what should happen according to the exercise?
This is roughly how a definition looks like in the dictionary using a traditional memory layout. Note that implementations may well diverge from this, sometimes a lot. In particular, the order of the fields may be different.
Link to previous word (one cell)
Flags (a few bits)
Name length (one byte, less a few bits)
Name string (variable)
Code field (one cell)
Parameter field (variable)
Everything except the code and parameter fields is considered the header. The code field usually comes right before the parameter field.
Ticking a word with ' gives you an XT, or execution token. This can be anything the implementation fancies, but in many cases it's the address of the code field.
Executing a word created with CREATE or VARIABLE gives you the address of the parameter field.
This is probably why in Win32Forth, the two addresses differ by 4 bytes, or one cell. I don't know why the answers to the exercises state there should be no difference.
Assuming BASE is a user variable, it probably works like this: Every task has its own user area in which user variables are allocated. All user variables know their specific offset inside this area. Ticking BASE gives you its XT, which is the same for all tasks. Executing BASE computes an address by adding its offset to the base of the user area.

Informix 4GL report to screen - Reverse

I have a generated report in Informix 4GL that prints to the screen.
I need to have one column displayed in reverse format.
I tried the following:
print line_image attribute(reverse)
But that doesn't work. Is this possible at all?
Adding on to the previous answer, you can try the following
print "\033[7mHello \033[0mWorld"
\033[7m means to print in reverse. And, \033[0m means to go back to standard.
If you mean "is there any way at all to do it", the answer's "yes". If you mean "is there a nice easy built-in way to do it", the answer's "no".
What you'll need to do is:
Determine the character sequence that switches to 'reverse' video — store the characters in a string variable brv (begin reverse video; choose your own name if you don't like mine).
Determine the character sequence that switches to 'normal' video — store the characters in a string variable erv (end reverse video).
Arrange for your printing to use:
PRINT COLUMN 1, first_lot_of_data,
COLUMN 37, brv, reverse_data,
COLUMN 52, erv,
COLUMN 56, next_lot_of_data
There'll probably be 3 or 4 characters needed to switch. Those characters will be counted by the column-counting code in the report.
Different terminal types will have different sequences. These days, the chances are your not dealing with the huge variety of actual green-screen terminals that were prevalent in the mid-80s, so you may be able to hardwire your findings for the brv and erv strings. OTOH, you may have to do some fancy footwork to find the correct sequences for different terminals at runtime. Shout if you need more information on this.
A simple way which might allow you to discover the relevant sequences is to run a program such as (this hasn't been anywhere near an I4GL compiler — there are probably syntax errors in it):
MAIN
DISPLAY "HI" AT 1,1
DISPLAY "REVERSE" AT 1,4 ATTRIBUTE(REVERSE)
DISPLAY "LO" AT 1, 12
SLEEP 2
END MAIN
Compile that into terminfo.4ge and run:
./terminfo.4ge # So you know what the screen looks like
./terminfo.4ge > out.file
There's a chance that won't use the display attributes. You'd see that if you run cat out.file and don't see the reverse flash up, then we have to work harder.
You could also look at the terminal entry in the termcap file or from the terminfo entry. Use infocmp $TERM (with the correct terminal type set in the environment variable) and look for the smso (enter standout mode) and rmso (exit standout mode) capabilities. Decipher those (I have rmso=\E[27m and smso=\E[7m for an xterm-256color terminal; the \E is ASCII ESC or \033) and use them in the brv and erv strings. Note that rmso is 5 characters long.

How to get the current paragraph name?

I would like to know how to get the current paragraph name in COBOL (using MVS Enterprise COBOL V4.2 here).
Let's say I have this code in the PROCEDURE DIVISION :
MAIN-LOGIC.
MOVE SPACE TO ABT-MSG
PERFORM PARAGRAPH-1
PERFORM PARAGRAPH-2
GO TO CLOSE-PROGRAM.
*
* SEARCH FOR A VALUE IN AN ARRAY AND GET THE RELATED INDEX
*
PARAGRAPH-1.
MOVE 42 TO SEARCH-VALUE
PERFORM VARYING I-SEARCH FROM 1 BY 1
UNTIL SOME-ARRAY(I-SEARCH) = SEARCH-VALUE
IF (I-SEARCH = MAX-ARRAY-POSITION)
MOVE SEARCH-ABORT TO ABT-MSG
MOVE 'PARAGRAPH-1' TO ABT-LOC
GO TO CLOSE-PROGRAM
END-IF
END-PERFORM
DISPLAY 'VALUE WAS FOUND AT POSITION ' I-SEARCH '.'.
*
* STORE A NEW VALUE AT THE END OF AN ARRAY
*
PARAGRAPH-2.
MOVE 42 TO STORAGE-VALUE
ADD 1 TO I-STORAGE
IF (I-STORAGE > MAX-ARRAY-POSITION)
MOVE STORAGE-ABORT TO ABT-MSG
MOVE 'PARAGRAPH-2' TO ABT-LOC
GO TO CLOSE-PROGRAM
END-IF
MOVE STORAGE-VALUE TO SOME-ARRAY(I-STORAGE).
*
* CLOSE THE PROGRAM
*
CLOSE-PROGRAM.
IF ABT-MSG > SPACE
DISPLAY ABT-MSG
DISPLAY '(FOUND IN ' ABT-LOC ')'
MOVE 20 TO RETURN-CODE
ELSE
DISPLAY SUCCESS-MESSAGE
END-IF
STOP RUN.
I would like to be able to access the current paragraph name (and store it in ABT-LOC) instead of having to write it.
Is there a COBOL system variable to do so, like 'CURR-PARA-NAME' or something ?
Thank you.
------ UPDATE 1 -------
I have updated my code example to make it more specific.
Know that, in my real COBOL program, there are various occurences of SEARCH-ABORT and STORAGE-ABORT possibilities (I am working with many arrays).
I want to make my code as good as possible, hence my will to access the current paragraph name instead of having to write it.
Thank you again.
------- UPDATE 2 ------
Well then. It seems I cannot do it (the users of my program will probably reject any debug messages they are not used to get - For your information, I am rewriting a 50 years old program with very, very bad programming practices such as upward GO TOs, fall-through logic and the godforsaken ALTER, and I want to get the same output at the end).
Don't worry, I will not cry tonight. This was just an esthetical improvement to my code, and I can live without it (my code is already a lot prettier than what I based myself on).
I thank all of you for your time, and wish you a good... Stack Overday !
As Simon Sobisch has correctly indicated in his answer, the only way to do exactly what you want is to use the "debugging declaratives". See later in the answer for making that work, but no-one should allow you to do this to a Production program.
COBOL is a compiled language so there is no no automatic access to any data-name or procedure name (paragraph or SECTION) unless the compiler makes something available. Which, excluding the case above, it doesn't.
That leaves three approaches: doing it manually (which you correctly want to avoid, as sure as peaches someone is going to copy or relocate code without changing the literal); pre-processing (with a program or the editor) to automatically populate your field with the correct label; doing something else.
Since you are implicitly discounting the first, again I believe correctly, let's consider the second. What if you have two, three or eight things in the same paragraph/SECTION which are all "business errors" (although usually these types of things are more "integrity errors", a state which should not exist, so don't continue)?
Since you will get those, a "pre-processing" solution starts to get more ugly.
What else can be done?
Well, it's something we've faced for many, many years. The answer is, unique (within the program) error numbers. The individual errors can be named, well, and given a number. The well-named error reference is difficult to use "incorrectly". When adding a new error, it is difficult to duplicate an existing number. Or, to put it another way, it is easy to duplicate but horribly easy to spot in testing - "hey, that's produced 1234, that's wrong".
It's in no way bullet-proof, but the data-name (and any associated text) give better indication of the problem than a paragraph-name (which is not going to be, except artificially, any indication of what the error is, just the location of it). The error references are very easy to find in the program, and from that it is easy to locate the procedure name, except you don't actually need it any more.
Whether the program with error-numbers outweigh the dross of manually maintained MOVE 'literal' TO some-standard-name programs is unknown. But you can guess which I favour and recommend.
Now, how to do it for Enterprise COBOL with DECLARATIVES.
IDENTIFICATION DIVISION.
PROGRAM-ID. STAB39.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SOURCE-COMPUTER. FRED DEBUGGING MODE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 W-WHEN-COMPILED PIC X(8)BX(8).
01 ABT-LOC PIC X(30).
PROCEDURE DIVISION.
DDECLARATIVES.
DSOME-SECTION SECTION.
D USE FOR DEBUGGING ON ALL PROCEDURES
D .
DSOME-PARA.
D MOVE DEBUG-NAME TO ABT-LOC
D .
DEND DECLARATIVES.
STARTING-UP SECTION.
DISPLAY
ABT-LOC
D DISPLAY
D "IT IS STARTING UP"
MOVE WHEN-COMPILED TO W-WHEN-COMPILED
DISPLAY
"STAB39 "
W-WHEN-COMPILED
.
A-PARA.
DISPLAY
ABT-LOC
PERFORM
10 TIMES
D DISPLAY
"ITERATING"
END-PERFORM
.
ANOTHER-PARA.
DISPLAY
ABT-LOC
PERFORM THE-PARA
10 TIMES
PERFORM THE-SECOND-PARA
GOBACK
.
THE-PARA.
DISPLAY
ABT-LOC
.
THE-SECOND-PARA.
DISPLAY
ABT-LOC
.
Some notes:
The SOURCE-COMPUTER paragraph is required to use COBOLs in-built debugging features, to turn them on. So the ENVIRONMENT DIVISION and CONFIGURATION SECTION are also required. The "computer name", FRED in the example, is required, but it is irrelevant. You can "name" your computer after your favourite pet or relative if you like, or put anything there, there just has to be something.
DECLARATIVES can only be specified at the start of the PROCEDURE DIVISION. They must be within a SECTION and all actions must be within a paragraph belonging to a SECTION. The names of the SECTION and paragraph are irrelevant, but make them meaningful anyway.
Because the DECLARATIVES must contain a SECTION, you will be subject to an informational diagnostic message if your first procedure label is not also a SECTION. This does not require using SECTIONS over paragraphs in your program, it has no further effect.
The D in column seven indicates a "debugging line". These lines only get code generated when you turn debugging on with the SOURCE-COMPUTER paragraph.
The program exercises all use of a paragraph (and use of a SECTION is no different for this example) except GO TO. Paragraphs which are GO TO'd will produce the same results as any other reference, but you won't see GO TOs in my programs :-)
It is possible to name the procedure or procedures you want to "trap" with the DECLARATIVES instead of using "ALL PROCEDURES".
You may have multiple DEBUGGING procedures, and you can include extensive code within them if you wish (setting up conditions for testing, for instance).
Although this feature has existed in COBOL for a long time, it is probably fair to say that it is not widely used, especially as specific "debugging products" became available.
It is not enough just to have this program, the "run time" needs to have DEBUG turned on, if it is not the default. The run-time on z/OS is called Language Environment and is shared by multiple languages (allowing easy inter-language communication). Languages include C/C++, PL/I and Java as well as COBOL. There are Language Environment routines and macros available to make HLASM/Assembler programs "LE Compliant" to also provide ready interfacing.
To see what run-time options your site has as default, the easiest thing to do is to include a CEEOPTS DD statement in your run JCL.
//CEEOPTS DD *
RPTOPTS(ON)
This will list out all the options used for your "Enclave" (your run environment) and indicate where each option is sourced from.
If, in the OPTION column, you see NODEBUG, then COBOL debugging is turned off by default. To turn it on for a particular run:
//CEEOPTS DD *
DEBUG
This will allow all the D-labelled debugging lines and the debugging DECLARATIVES to execute.
This will do what you want, but no-one will allow a program with debugging on into Production, so you can't use it for what you want.
In order of preference, I advise error-numbers (and testing), automation, hand-coded procedure-name literals.
IBM fully documents all its products, and you can find the documentation (Language Reference and Programming Guide amongst others) for Enterprise COBOL V4.2 and also Language Environment (several) for your release of z/OS.
One final point. Don't use GO TO to "break out" of your normal processing flow. Use PERFORM. Even when, logically, the PERFORM cannot return. Using GO TO will turn off compiler optimisation for paragraphs/SECTIONs containing the GO TO which can easily cause a noticeable impact on execution. This is the reverse of the advice from before IBM COBOL ensured that the state of PERFORMed paragraphs/SECTIONs is not preserved between CALLs. At that time the correct advice was to use GO TO. It is no longer the correct advice.
As you have the pseudo-code "something bad happened here" I assume an exception. In this case the standard (COBOL 2002, COBOL 2014) function EXCEPTION-LOCATION may help (although the actual string is implementor-defined I assume the paragraph may be in there [GnuCOBOL for example has the format: program-id; paragraph [or paragraph OF section or section, depending on your program]; source-line]).
If your COBOL compiler provides this information in this function and there is no exception in the offending part already: create one via subtract 1 from unsigned-var or similar.
As Bill already said (or implied): this is a question where the actual COBOL compiler used will be the most important part if you must have the names in as identifier and as label or not.
Edit (after the actual COBOL compiler is known):
IBM MVS Enterprise COBOL doesn't have the EXCEPTION-LOCATION function. Therefore I see only one built-in solution:
DECLARATIVES.
debug-declaratives SECTION.
USE FOR DEBUGGING ON ALL PROCEDURES.
debug-par.
MOVE debug-name TO current-procedure.
END DECLARATIVES.
But as this is only active if your program runs in debugging-mode (which may causes a lot of debugging messages to occur) I don't suggest to actual use this.
Try to use an Editor providing macros (or run a shell script on your actual source) to create the source you pass to the compiler afterwards.

Is there a list of Special characters to be avoided in JCL/MVS Script variables

I have a program that generates random pin codes. These pins are generated in Java, then stored in the mainframe, via a NATURAL program. From there, they are eventually physically printed by a batch JCL job that calls an MVS SCRIPT to print the form, with the pin code on it.
I've come across some issues with special characters before such as: |{}![]^~<>; that for one reason or another do not print properly. I've also removed 0OQ1l for OCR reasons.
Recently, an error came to my attention with another character that doesn't print properly, . but the . character only fails when it is the first character of the PIN Code.
So since I've run into this issue I thought I would see if I could find other special jcl, Natural or MVS Script characters that might interfere with my programs operation so that I can test them now and hopefully not run into this issue later or have to fallback to only using OCR'ed AlphaNumeric characters.
EDIT
Java - Web Application Runs Under Tomcat 6.x on a Solaris Server.
Natural - The Natural Program is called using webmethods Broker generated classes (POJOs).
My understanding is it uses RPC for actual communication.
The program verifies some data and stores the Pin in combination with a GUID on a record, in ADABAS.
There is a batch job that runs to print the forms. The Batch job is written in JCL.
My Understanding from the maintainer of the Batch Job, and the Forms stuff is the actual language to describe the forms themselves and how they get printed is an outdated/unsupported language called MVS SCRIPT.
the Bottom section of the script looks like this:
//**********************************************************************
//* PRINT SORTED FORMS TO #### USING MVS SCRIPT
//**********************************************************************
PRINTALL EXEC PGM=DSMSPEXEC,PARM='LIST'
//* less 'interesting' lines omitted
SYSPRINT DD SYSOUT=*
PRINT1 DD SYSOUT=A, OUTPUT=*.C####,
RECFM=VBM,LRECL=####,BLKSIZE=####
//* less 'interesting' lines omitted
//SYSIN DD *
AUTH /* redacted */
SCRIPT FROM(MYFORMS) (MESSAGE(ID TRACE) CONT -
FILE(PRINT1) PROFILE(redacted) -
NOSEGLIB DEVICE(PG4A) CHARS(X0A055BC))
.C#### is an actual number and is a variable that points to the chosen printer.
NOTE: I'm a Web Programmer, I don't speak mainframe, JCL, MVS, etc.
I think you will find the program (pgm=) is DSMSPEXC and not DSMSPEXEC.
I am guessing (could be wrong) we are talking about Script/DCF (which later became IBM Bookmaster / Bookmanager on other platforms).
Script/DCF is basically a GML based language. It was from GML that SGML was derived (HTML and XML are prominent examples of SGML languages).
In Script : starts a tag, . ends a tag. There are also macro's which have a . in column 1
.* ".*" in column 1 starts a line comment
.* .fo off is Format off (like <pre> in html)
.fo off
.* Starting an ordered list
:ol.
:li.Item in orded list
:eol.
i.e.
Script HTML
: < - Starts tag
. > - end of tag Script/DCF is generally pretty tolerant of .
& & - Starts a variable
There are variables (&gml. = :) for most of the special characters.
Characters to worry about are
: - always
& - always
. - in column one or after a :.
Other characters should be ok provided there are no translation errors. There charset X0A055BC (Mainframe SONORAN SANS SERIF ??) might not have all the special chars in it.
There are manuals around for Script/DCF tags.
Your data is not going to affect the JCL in any way.
I don't know about ADABAS or NATURAL. If you ask here, http://www.ibmmainframeforum.com/viewforum.php?f=25, specifically about that part, with as much detail as you can provide, there is a very expert guy, RDZbrog, who can probably answer that for you.
For the SCRIPT/VS itself, as Bruce Martin has pointed out, there may be some issues. With .xx and :xx there is not a clash with normal text. But you don't have normal text. With the &, which indicates a SCRIPT variable, it is more likely to be problematic and at any location.
I would fire some test data through: Your PINs with position one being all available punctuation preceding "fo" and "ol", and the same with those sequences "embedded" in your PINs. Also include a double & and a triple &.
Your query should be resolved in your specification. It is not, but I'm sure you'll get all the documentation updated when you get a resolution.

Resources