[comp.lang.forth] Formatting Forth source code

ForthNet@willett.UUCP (ForthNet articles from GEnie) (08/01/90)

Category 2,  Topic 13
Message 4         Mon Jul 30, 1990
W.BADEN1 [Wil]               at 19:23 PDT
 
Every Forth programmer believes his code is readable.

Other programmers, even other Forth programmers, seldom agree with him.

I'm looking for short but non-trivial examples of code that you believe is
readable.

No one can make Forth code absolutely readable, but I believe I can make most
code more readable.  I want to test my method and verify it or find a better
method.

This is a daring challenge on my part and I may convince no one but myself but
I am confident enough to try.

If no one submits anything I will take it as a personal confession that you do
not write readable Forth code.

Procedamus in pace.
-----
This message came from GEnie via willett through a semi-automated process.
Report problems to: uunet!willett!dwp or willett!dwp@hobbes.cert.sei.cmu.edu

wmb@MITCH.ENG.SUN.COM (Mitch Bradley) (08/01/90)

Wil Baden> I'm looking for short but non-trivial examples of code that you
Wil Baden> believe is readable.

I hereby submit the following implementation of CATCH/THROW.  Go to it, Wil!

\ CATCH/THROW Error Handling Wordset
\ by Mitch Bradley
\

\ This implementation uses the non-standard words SP@ , SP! , RP@ , and
\ RP! .  These words, or their equivalents, are present in most systems.
\ Another implementation which does not use those non-standard words
\ follows this implementation.

\ Thanks to Don Colburn and Dean Sanderson for implementation suggestions.

VARIABLE HANDLER  \ Most recent error handler (should be a USER variable)

: CATCH  ( cfa -- error# | 0 )
   			( cfa )  \ Return address is already on the stack
   SP@ >R		( cfa )  \ Save data stack pointer
   EXCEPTION @ >R	( cfa )  \ Previous handler
   RP@ HANDLER !	( cfa )  \ Set current handler to this one
   EXECUTE		( )      \ Execute the word passed in on the stack
   R> HANDLER !		( )    	 \ Restore previous handler
   R> DROP		( )      \ Discard saved stack pointer
   0   			( 0 )    \ Signify normal completion
;

: THROW  ( ??? error# -- ??? error# ) \ Returns in saved context
   ?DUP  IF
      HANDLER @ RP!	( err# )      \ Return to saved return stack context
      R> HANDLER !	( err# )      \ Restore previous handler

      \ Remember error# on return stack before changing data stack pointer

      R> SWAP >R	( saved-sp )  \ err# is on return stack
      SP! R>		( err# )      \ Change stack pointer

      \ This return will return to the caller of catch, because the return
      \ stack has been restored to the state that existed when CATCH began
      \ execution .
   THEN
;

wmb@MITCH.ENG.SUN.COM (Mitch Bradley) (08/01/90)

Wil Baden> I'm looking for short but non-trivial examples of code that you
Wil Baden> believe is readable.

Another "readable code" submission:

\ LEFT-PARSE-STRING  ( adr len char -- adra lena  adrb lenb )
\ Splits a string into two halves around a delimiter character.
\ If the delimiter character is present in the string, adra lena is the
\ substring after the first occurrence of the character, adrb lenb
\ is the substring before it.
\ Both substrings exclude the character itself.
\
\ If the character is not present in the string, the original string
\ adr len is returned, and the flag on top of the stack is false.

\ Removes max(n,len) characters from the beginning of the string "adr len"
: /string  ( adr len n -- adr+len adr-len )
   over min >r  swap r@ +  swap r> -
;
: +string  ( adr len -- adr len+1 )  1+  ;
: -string  ( adr len -- adr+1 len-1 )  swap 1+  swap 1-  ;

\ adra,lena is the string after the delimiter
\ adrb,lenb is the string before the delimiter
\ lena = 0 if there was no delimiter

: left-parse-string  ( adr len char -- adra lena  adrb lenb  )
   >r  over 0  2swap                ( adrb 0  adra lena )

   \ Throughout the loop, we maintain both substrings.  Each time through,
   \ we add a character to the first string and remove it from the second.
   \ The loop terminates when either the second string is empty or the
   \ desired character is found

   begin  dup  while                  ( adr0 len0  adr1 len1 )
      over c@  r@ =  if               \ Found it; exchange strings
         r> drop -string 2swap exit   ( adra lena  adrb lenb )
      then
      2swap +string  2swap -string    ( adr0 len0  adr1 len1 )
   repeat                             ( adr0 len0  adr1 len1 )

   \ Character not found.  len1 is 0.
   2swap                              ( adra lena  adrb lenb )
   r> drop
;

ForthNet@willett.pgh.pa.us (ForthNet articles from GEnie) (01/12/91)

Category 2,  Topic 13
Message 9         Thu Jan 10, 1991
B.RODRIGUEZ2 [Brad]          at 07:32 EST
 
Well, maybe I'm missing something here, but I've had no trouble producing
standalone/turnkey applications for my PC using LOVE- 83Forth and PC
PowerForth.  And that's not even counting TCOM, which I have but don't (yet)
use.

Now, if your gripe is that there's no _standard_ way to do this, you have a
valid (although perhaps trivial) point.

- Brad
-----
This message came from GEnie via willett.  You cannot Reply to the author
using email.  Please post a follow-up article, or use any instructions
the author may have included (USMail addresses, telephone #, whatever).
Report problems to: dwp@willett.pgh.pa.us or uunet!willett!dwp

ForthNet@willett.pgh.pa.us (ForthNet articles from GEnie) (03/30/91)

Category 2,  Topic 13
Message 18        Mon Mar 25, 1991
ATFURMAN [Alan F.]           at 23:50 PST
 
Mitch Bradley writes:

 > Those languages tend to start out with a relatively straightforward
 > syntactic structure...After awhile it degenerates into a massive kludge.

Syntactic diabetes.
-----
This message came from GEnie via willett.  You *cannot* reply to the author
using e-mail.  Please post a follow-up article, or use any instructions
the author may have included (USMail addresses, telephone #, etc.).
Report problems to: dwp@willett.pgh.pa.us _or_ uunet!willett!dwp

ForthNet@willett.pgh.pa.us (ForthNet articles from GEnie) (05/13/91)

Category 2,  Topic 13
Message 19        Wed May 08, 1991
R.CAVANAUGH [BobC]           at 23:38 MDT
 
In keeping with the spirit, here is my prefered way of formatting:

( F - PC dialect )


\ Modified query to select maximum number of input

: nquery ( n -- )
    tib swap expect                     \ get digits from in stream
    span @ #tib !                       \ store number of inputs
    >in off                             \ reset input pointer
 ;

\ General purpose routine to
 \ input a number from the user


: get-num ( #digits base -- dnum flag ) \ flag - true for valid

    base @ >r !                         \ save current base, load new
    ." ?"                               \ prompt for input
    nquery                              \ get <= #digits from input
    bl word                             \ convert to counted str
    ?uppercase                          \ if hex, make sure upper
    number?                             \ convert string to number
    r> base !                           \ restore old base
 ;

- Notes

1. If my words require detailed stack diagrams at each line,
   I feel I need to rethink how I am doing it.  Input stack condition
   and output I feel should be sufficient

2. Each line should be functionally related, i.e. I would put
   " 1 junk +! " as one line as incrementing a variable
   is really one action, whereas
   " something-to-test n =
     if
         do-if-true
     else
         do-if-false
     then
   "
   is the way I like to structure conditionals.  I can take a ruler
   (or the col indicator on my editor) and see the subdivisions
   of the algorithm.

3. I am a strong proponent of line-by-line comments, as to what you
   are trying to do.  I find this helps me a great deal when I come
   back to code (in any language) n years later and try to reuse
   or modify it.  The flow of how I thought out what I was doing
   rings bells, and I have found aids my collegues in understanding
   and maintaining the code.  I find the effort required pays later.
 - Bobc
-----
This message came from GEnie via willett.  You *cannot* reply to the author
using e-mail.  Please post a follow-up article, or use any instructions
the author may have included (USMail addresses, telephone #, etc.).
Report problems to: dwp@willett.pgh.pa.us _or_ uunet!willett!dwp

ForthNet@willett.pgh.pa.us (ForthNet articles from GEnie) (05/13/91)

Category 2,  Topic 13
Message 20        Fri May 10, 1991
D.RUFFER [Dennis]            at 01:31 EDT
 
Bob, just a couple of comments on your formatting style (:since you opened
yourself up to it:)

Lower case:

I've seen many people adopt this before, and I can understand how someone who
has a background in other languages (that aren't case sensitive) might prefer
it.  However, in my opinion, those people and languages are throwing away half
the alphabet.  I prefer to work with Forth's that _are_ case sensitive, and I
tend to use lower case for low level words.  That way, I have a built in
indication of user interface words, with easy to remember sublayers.

Comment/phrase:

I used to work (some 12 years ago) on RPG programs written by IBM programmers.
They tend to comment everything and in some cases it got to the point that
could not even find the "real" source code lines.  Personally, I can read the
code much better than I can read the comments, that is why I work in a given
language.  At the most, all I care about is a brief description of _why_ a
given module is needed.  I _do not_ need a comment that tells me that the
phrase: >IN OFF  resets the input stream.  Something like that just "gets in
the way" when I'm trying to figure a section of code out.

My personal opinion is that you should be able to _read_ Forth source code. 
The names should be choosen carefully so that the resulting modules "say" what
they do.  Some of this comes from internal naming conventions (i.e. "/" means
initialize, ">" means pointer to..., etc.), but most comes from imaginitive
vocabularies (i.e. a thesaurus).

Vertical coding:

Maybe this comes from my long time work with BLOCK files, but putting only a
few things on a line seems to be wasteful to me.  For me, 2 spaces is enough
to seperate phases within Forth.  I want to get as much of a given concept as
I can on 1 page.  As far as lining up structures goes, I sometimes find that
useful, but again, I will only use it if the vertical space is not overused.

Stack diagrams:

Absolutely essential at the beginning of the word, but I agree with you about
line by line analysis.  If it is that hard to understand what is happening on
the stack, then the word should be refactored.

Comments in general:

Not to belabor the point, but I feel that it is important.  A comment that
tells me _what_ something does is not near as useful as a comment that tells
me _why_ it does it.  What can be determined by examining the code, but why is
often buried within the designer's mind.  As a manager, a programmer's time if
very valuable.  I do not want him/her spending that time duplicating efforts
by restating what the code does.  Rather, I value the time invested in
recording the reasons why the program is organized that way it is.  It is much
harder to write (as a programmer) but much more valuable years later when the
original programmer may not even be available for consultation.

Just some thoughts.   :)   DaR
-----
This message came from GEnie via willett.  You *cannot* reply to the author
using e-mail.  Please post a follow-up article, or use any instructions
the author may have included (USMail addresses, telephone #, etc.).
Report problems to: dwp@willett.pgh.pa.us _or_ uunet!willett!dwp

ForthNet@willett.pgh.pa.us (ForthNet articles from GEnie) (05/13/91)

Category 2,  Topic 13
Message 21        Fri May 10, 1991
G.LEFAVE [Gene]              at 14:18 CDT
 
I've spent many years trying to decide this question.  I have come to favor
Dennis's style for the following reasons.

1.  Block oriented text generally gets a couple of entire definitons on the
screen at once.

2.  Shadow blocks and the simple forth index are the easiest way I've found to
understand a program.  One can read the shadow's to find the point in a
program that is of interest, then read the source.

3. Empty shadow blocks are painfully obvious on a listing and encourage
programmers to fill them in.


My own style is to try to terminate the lines with branching words. But I have
to confess to having been taught by Kim Harris.  A proponent of that style, 
the idea being that Forth using RPN notation should actually be indented from
the right.
       .......           IF
         ...............
       ........        ELSE
         ...............
       ........        THEN

I try not to get in these discussions, they're just as bad as the {} debates
in another language.


-----
This message came from GEnie via willett.  You *cannot* reply to the author
using e-mail.  Please post a follow-up article, or use any instructions
the author may have included (USMail addresses, telephone #, etc.).
Report problems to: dwp@willett.pgh.pa.us _or_ uunet!willett!dwp

ForthNet@willett.pgh.pa.us (ForthNet articles from GEnie) (05/13/91)

Category 2,  Topic 13
Message 22        Fri May 10, 1991
D.RUFFER [Dennis]            at 22:30 EDT
 
Gene, I also have been influenced by Kim Harris' coding conventions. For those
who have never seen it, find the 1985 FORML Conference Proceedings.  Pages 143-
74 contain his paper on "Forth Coding Conventions".  It is worth reading by
anyone who is concerned about programming style.

Gene, you also mentioned "shadow" blocks.  For those not familar with them,
they are a mapping of source blocks to documentation blocks in a 1 to 1
relationship.  In some cases, the second half of the file is reserved for
them, in others a whole nother block file is created to hold them.  They allow
a simple facility to be created to manage them (i.e. one word to switch back
and forth).  However, although I use them, I've found that a block is even
more limiting for documentation than it is for source.  I'm always running out
of room and then I have to leave something out.  While they do accomplish the
goal of getting the documentation both out of the way of the source and
connected to it at the same time, they are not the panacea that I have been
searching for.

DaR
-----
This message came from GEnie via willett.  You *cannot* reply to the author
using e-mail.  Please post a follow-up article, or use any instructions
the author may have included (USMail addresses, telephone #, etc.).
Report problems to: dwp@willett.pgh.pa.us _or_ uunet!willett!dwp

ForthNet@willett.pgh.pa.us (ForthNet articles from GEnie) (05/13/91)

Category 2,  Topic 13
Message 24        Sat May 11, 1991
R.CAVANAUGH [BobC]           at 00:10 MDT
 
Dennis,

Thanks for the thoughts! I have used lower case in C, using caps for user
definitions (such as #define MYTHING) and the habit has stuck. For some
reason, small case seems more "friendly", but you raise a good point.  As far
as comments form vs function, I usually try to highlight items of a particular
language that someone who does not know the syntax intimately can follow
what's happening.  As the example I used was getting into some of the inner
workings of that forth, I was much more detailed than I would be for say
 10 0 i . loop, which is one reasonably encapsulated and obvious. Since I work
with a text-oriented forth, vertical and logical block spacing is again
natural to me from the C world.  By the way, re the post on eForth, how do I
find out more about polyForth ? Thanks

-- Bobc
-----
This message came from GEnie via willett.  You *cannot* reply to the author
using e-mail.  Please post a follow-up article, or use any instructions
the author may have included (USMail addresses, telephone #, etc.).
Report problems to: dwp@willett.pgh.pa.us _or_ uunet!willett!dwp