• MAC SELECT construct

    From Mr. Emmanuel Roche, France@21:1/5 to All on Sat Nov 6 14:14:31 2021
    MAC SELECT construct by Mr. Emmanuel ROCHE, France
    --------------------

    Ok. As usual, it started innocently. While searching for something else, I saw a mention of Henry Ledgard, the author of the classic "Programming Proverbs". This man wrote only a handful of books, but I find them much more interesting than others (and
    well written). There is also the famous "The emperor with no clothes" article, published in the "Commun. ACM" in 2001. "Nothing new under the Sun", alas!

    I made a search. Curiously, Wikipedia has no page on him. I found a Web page listing some of his books... in Germany!

    https://dblp.org/pid/26/6957.html

    It is there that I found mention of "A Genealogy of Control Structures", an article that I had not read. 36 pages later, my interest in "Control Structures" was revived. Now, it happens that, 6 weeks ago, there was a thread, in the comp.os.cpm Newsgroup,
    about SEQIO.LIB, a library of macros that was published in the "CP/M MAC Macro Assembler" manual, starting in 1977. And I remembered that this manual happens to contain on "Program Control Structures" Section...

    As usual, I have no idea where my stuff is, so I searched on the Internet if someone had uploaded the MAC manual. I found the 1980 version, that I downloaded, then printed the pages of the Section.

    As Bohn & Jacopini demonstrated in 1966(!), everything that can be programmed can be reduced to only 3 "control structures":

    1) sequence of instructions (LET... LET...)
    2) controled iteration (FOR-NEXT)
    3) case selection (IF-THEN-ELSE)

    https://en.wikipedia.org/wiki/Structured_program_theorem

    Depending on their domains, some Programming Languages have more specialized control structures but, to be "universal", a PL must have, one way or another, at least those 3 control constructs.

    So, the MAC manual contains:

    1) WHEN-ENDW (conditional grouping)
    2) controlled iteration (DO-ENDDO)
    3) case selection (SELECT-ENDSEL)

    (a sequence of ASM instructions should be obvious)

    allowing one to produce Intel 8080 assembly languages with those high-level control constructs. Very educational. Nothing like that can be found in MicroShit manuals. You can feel that Gary Kildall was a Teacher of Computer Science.

    Ok. Now, how to recreate those macros? At my age, with my sight, it would be a pain in the Accumulator to retype the source codes. I searched inside my computer, and found one directory named "MAC Macros". One less work to do. I found them unreadable
    since they are written in upper case only. (When Gary Kildall created Digital Research, he complained that he had heard the ASR-33 Teletype during 2 years at the Naval Postgraduate School of Monterey, California! Since CP/M first booted in April 1974 and
    he created DRI in 1976, he was right.) So, I edited the files to be more readable. Now, time for a test.

    I assembled the first example program. No problem, except that the messages displayed on the screen were in upper case, when the source file was in lower case. But this gives an "Old Style" to the programs.

    I continued. No problem, until I arrived to SELECT, the last construct.

    After 30+ years of assembly programming, I could not escape the fact the hex columns of the PRN files were 3 bytes away from the published PRN files! All the other ASM files had produced the same PRN files as the MAC manual, but not this one!?!

    I wondered: "Maybe they changed something in this 1980 revision?" So, I searched for the 1977 version, and found it on BitSavers. However, impossible to find a difference!

    So, I made another search among the files of my Internet computer, and found a ZIP file containing the MAC macros. When I used it (I mean: SELECT.LIB), it produced the PRN files of the manual! Haaaaa!... (the programmer's national anthem). All I had to
    do, now, was to find the difference. Which is: one line was missing in this version, which has been present since 1977 in the MAC manual. So, apparently, this file was a copy of the MAC macros made circa 1976, when Digital Research was launched, and
    religiously preserved ever since then.

    I think that I am a little bit knowledgeable about CP/M and its utilities, but I have never heard of this bug. So, in case someone else understands what I write, here are the "bugs" that I found in the MAC manual:

    MAC Section 9.3 errata
    ----------------------

    Page 117, second paragraph from the bottom of the page:

    "Upon encountering [THE] an ENDW statement in the source program, ..."

    Page 123, third paragraph from the bottom of the page:

    (...) the CR-LF on each i[N]teration, ..."

    Page 128, bottom of SELECT macro:

    select var
    selnext ;; Automatically select case 0
    ENDM

    Page 134, bottom of Figure 51:

    WRITE <so I^'^'m going back^!>

    Of course, if you use SELECT with the SELNEXT line, the 3 listings of Figure 50 will no longer correspond with the ones of the MAC manual. Apparently, I am the first person to notice this in the last 44 years. This must be progress? (Re-read the "Emperor"
    article.)

    Yours Sincerely,
    Mr. Emmanuel Roche, France

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Martin@21:1/5 to Martin on Sun Nov 7 14:57:30 2021
    Am 11/07/2021 02:41 PM, Martin schrieb:
    And if we are at it, here are real *BUGS* !!!

    First a test progam "compbug.asm" to show the problem.
    It compares the correct "LEQ" with the buggy "GTR" Macro.

    ===== 8< =====
    maclib compbug

    bdos equ 0005h
    arg1 equ 005dh
    arg2 equ 006dh

    org 100h

    mvi e,'1'
    lda arg1
    leq ,arg2,xleqa
    dcr e
    xleqa:

    mvi d,'0'
    lda arg1
    gtr ,arg2,xgtra
    inr d
    xgtra:

    xchg
    shld msg1

    mvi c,9
    lxi d,msg1
    call 5

    ret

    msg1: ds 2
    db 0dh,0ah,'$'
    ===== 8< =====


    Ooops!

    While testing, I renamed the buggy "COMPARE.LIB" to "COMPBUG.LIB".
    You likely didn't, so please change "maclib compbug" back to "maclib compare".


    Martin

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Martin@21:1/5 to France on Sun Nov 7 14:41:53 2021
    Am 11/06/2021 10:14 PM, Mr. Emmanuel Roche, France schrieb:
    MAC SELECT construct by Mr. Emmanuel ROCHE, France
    --------------------

    [...]

    So, I made another search among the files of my Internet computer,
    and found a ZIP file containing the MAC macros.
    When I used it (I mean: SELECT.LIB), it produced the PRN files of the manual!
    Haaaaa!... (the programmer's national anthem).
    All I had to do, now, was to find the difference.
    Which is: one line was missing in this version,

    The correct version of the macro *is* the newer one without the SELNEXT line.

    I think that I am a little bit knowledgeable about CP/M and its utilities,
    but I have never heard of this bug.
    So, in case someone else understands what I write,
    here are the "bugs" that I found in the MAC manual:

    MAC Section 9.3 errata
    ----------------------

    Page 117, second paragraph from the bottom of the page:
    "Upon encountering [THE] an ENDW statement in the source program, ..."

    Page 123, third paragraph from the bottom of the page:
    (...) the CR-LF on each i[N]teration, ..."

    Page 128, bottom of SELECT macro:

    select var
    selnext ;; Automatically select case 0

    This line above was *removed* in the fixed version.

    ENDM


    Page 134, bottom of Figure 51:

    WRITE <so I^'^'m going back^!>

    Of course, if you use SELECT with the SELNEXT line,
    the 3 listings of Figure 50 will no longer correspond with the ones of the MAC manual.
    Apparently, I am the first person to notice this in the last 44 years.
    This must be progress? (Re-read the "Emperor" article.)


    And if we are at it, here are real *BUGS* !!!

    First a test progam "compbug.asm" to show the problem.
    It compares the correct "LEQ" with the buggy "GTR" Macro.

    ===== 8< =====
    maclib compbug

    bdos equ 0005h
    arg1 equ 005dh
    arg2 equ 006dh

    org 100h

    mvi e,'1'
    lda arg1
    leq ,arg2,xleqa
    dcr e
    xleqa:

    mvi d,'0'
    lda arg1
    gtr ,arg2,xgtra
    inr d
    xgtra:

    xchg
    shld msg1

    mvi c,9
    lxi d,msg1
    call 5

    ret

    msg1: ds 2
    db 0dh,0ah,'$'
    ===== 8< =====


    Compile...

    mac compbug.aaa
    CP/M MACRO ASSEM 2.0
    0133
    002H USE FACTOR
    END OF ASSEMBLY

    load compbug

    FIRST ADDRESS 0100
    LAST ADDRESS 0132
    BYTES READ 0031
    RECORDS WRITTEN 01


    Execute with different values...

    compbug 2 1
    00

    compbug 2 2
    10

    compbug 2 3
    11


    Doesn't look very right ???



    Both "COMPARE.LUB" (Page 107, Figure 41) and
    "NCOMPARE.LIB" (Page 112, Figure 43a) are at fault:

    Replace the lines
    DCR A
    JNC TL
    with
    JNZ TL


    1) Macro "GTR" in "COMPARE.LUB"

    Fixed version:
    ===== 8< =====
    ;
    GTR MACRO X,Y,TL
    ;; X GREATER THAN Y TEST
    LOCAL FL ;;FALSE LABEL
    TEST? X,Y
    JC FL
    JNZ TL
    FL: ENDM
    ===== 8< =====


    2) Macro "GTR" in "NCOMPARE.LUB"

    Fixed version:
    ===== 8< =====
    ;
    GTR MACRO X,Y,TL,FL
    ;; X GREATER THAN Y TEST
    IF NUL TL
    LEQ X,Y,FL
    ELSE
    LOCAL GFL ;;FALSE LABEL
    TEST? X,Y
    JC GFL
    JNZ TL
    GFL: ENDM
    ===== 8< =====


    3) Macro "LEQ" in "NCOMPARE.LIB" has another BUG:

    The line
    GEQ X,Y,FL
    should be replaced with
    GTR X,Y,FL

    The fixed version:
    ===== 8< =====
    ;
    LEQ MACRO X,Y,TL,FL
    ;; X LESS THAN OR EQUAL TO Y TEST
    IF NUL TL
    GTR X,Y,FL
    ELSE
    LSS X,Y,TL
    JZ TL
    ENDM
    ===== 8< =====


    Yours Sincerely,
    Mr. Emmanuel Roche, France


    Have fun!
    Martin

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr. Emmanuel Roche, France@21:1/5 to Martin on Sun Nov 7 07:09:26 2021
    "Martin" <this.is.usenet@so.its.invalid> wrote:

    The correct version of the macro *is* the newer one without the SELNEXT line.

    ? The MAC manual was published in 1977, then revised in 1980. In both versions, we find the following remark:

    "At the end of the redefined SELECT macro, SELNEXT is invoked automatically to delimit the first case in the SELECT group (otherwise SELECT would have to be followed immediately by SELNEXT in the user program to generate the proper labels)."

    So, it seems quite surprising that nobody at DRI would have noticed that the SELNEXT line was... er, redundant?

    Also, why would later versions of the WHEN library contain this line, while only one copy found so far (presumed to be the oldest one) contains it?

    At least, the MAC manual documents this line.

    (Regarding your bugs, tomorrow, I am busy. So, I will investigate them later. Also, it would be more logical to use the SIMPIO library. Macros exist to make more high level assembly language programs, so why not use them?)

    Yours Sincerely,
    Mr. Emmanuel Roche, France

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Martin@21:1/5 to France on Mon Nov 8 20:10:29 2021
    Am 11/07/2021 04:09 PM, Mr. Emmanuel Roche, France schrieb:
    "Martin" <this.is.usenet@so.its.invalid> wrote:

    The correct version of the macro *is* the newer one without the SELNEXT line.

    ? The MAC manual was published in 1977, then revised in 1980. In both versions, we find the following remark:

    "At the end of the redefined SELECT macro, SELNEXT is invoked automatically to delimit the first case in the SELECT group (otherwise SELECT would have to be followed immediately by SELNEXT in the user program to generate the proper labels)."

    So, it seems quite surprising that nobody at DRI would have noticed that the SELNEXT line was... er, redundant?

    Also, why would later versions of the WHEN library contain this line, while only one copy found so far (presumed to be the oldest one) contains it?

    At least, the MAC manual documents this line.

    (Regarding your bugs, tomorrow, I am busy. So, I will investigate them later. Also, it would be more logical to use the SIMPIO library. Macros exist to make more high level assembly language programs, so why not use them?)

    Yours Sincerely,
    Mr. Emmanuel Roche, France


    Ahhhh! :-)
    Finally, I see it!

    The SELNEXT was not added or removed,
    it was moved into the redefined SELECT Macro!

    The buggy version in the manual from 1977 only works
    *THE FIRST TIME*!

    The SELNEXT is only invoked in the original SELECT,
    the redefined SELECT does not contain the SELNEXT anymore.

    [...]
    XCHG ;;READY BRANCH ADDRESS IN HL
    PCHL ;;GONE TO THE PROPER CASE
    ECNT SET 0 ;;ELEMENT COUNTER RESET
    ENDM
    ;; INVOKE REDEFINED SELECT THE FIRST TIME
    SELECT VAR
    SELNEXT ;;AUTOMATICALLY SELECT CASE 0
    ENDM
    [...]


    In the correct version of SELECT.LIB inside <http://www.retroarchive.org/cpm/archive/unofficial/download/mac-b.zip>
    SELNEXT is invoked *EVERY TIME* the redefined SELECT Macro is used.

    This is the correct version, comparing the output of the sample program
    at page 130 with both versions of SELECT.LIB shows it clearly.

    [...]
    XCHG ;;READY BRANCH ADDRESS IN HL
    PCHL ;;GONE TO THE PROPER CASE
    ECNT SET 0 ;;ELEMENT COUNTER RESET
    SELNEXT ;;SELECT CASE 0
    ENDM
    ;; INVOKE REDEFINED SELECT THE FIRST TIME
    SELECT VAR
    ENDM
    [...]


    Martin

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr. Emmanuel Roche, France@21:1/5 to All on Mon Nov 8 13:13:38 2021
    I wrote: "As usual, it started innocently." Hahaha! Indeed! I have been wondering all day long how to prove the good functioning of macros.

    Along the way, I found:

    1) The ASM file of Figure 44A and the PRN file of Figure 44B should have the following lines indented one way or another, to show the generated code:

    GTR x,%'z',NoTran
    lda x
    ani 0101$1111b ; Clear lower case bit
    sta x ; Store back to X

    2) The pseudo-code between Figure 49b and Figure 50a should have the following 2 lines:

    LDA id
    LXI H,SelV0

    3) I have had a little bit of difficulty understanding what "Martin" was trying to say. In short, the macro SELECT must contain one SELNEXT line. The problem is that, since 1977, the MAC manual was showing it in the wrong place in the SELECT macro! So,
    the good code is:

    ecnt SET 0 ;; Element counter reset
    selnext ;; Select CASE 0
    ENDM
    ;; Invoke redefined SELECT the first time
    select var
    ENDM

    (In English: the SELNEXT in *INSIDE* the firs ENDM, not before the second ENDM.)

    As usual, being a programmer, I prefer that the code do the talking.

    I think that the following is reasonable proof that this SELECT construct works:

    fig51

    SAMPLE CONTROL STRUCTURES
    TYPE SINGLE CHARACTERS FROM
    A TO D, I'LL STOP ON D
    TYPE A CHARACTER: e
    BAD CHARACTER
    TYPE A CHARACTER: a
    YOU SELECTED CASE A
    TYPE A CHARACTER: b
    YOU SELECTED CASE B
    TYPE A CHARACTER: c
    YOU SELECTED CASE C
    TYPE A CHARACTER: d
    YOU SELECTED CASE D
    SO I'M GOING BACK!


    4) As you may have seen, macros are funny. So, I have more questions.

    - Anybody knows how to change WRITE so that it does not convert all the strings to upper case?

    - Anybody has a working FOR-NEXT construct?

    - Anybody has an IF-THEN-ELSE construct? (Since these are "keywords" of MAC, one way would be to use the French words SI-ALORS-SINON. The closing ENDIF would then be ENDSI.)

    Yours Sincerely,
    Mr. Emmanuel Roche, France

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dxforth@21:1/5 to France on Tue Nov 9 15:07:22 2021
    On 9/11/2021 08:13, Mr. Emmanuel Roche, France wrote:
    ...
    4) As you may have seen, macros are funny. So, I have more questions.

    - Anybody knows how to change WRITE so that it does not convert all the strings to upper case?

    - Anybody has a working FOR-NEXT construct?

    - Anybody has an IF-THEN-ELSE construct? (Since these are "keywords" of MAC, one way would be to use the French words SI-ALORS-SINON. The closing ENDIF would then be ENDSI.)

    Perhaps it's just me but simulating HLL control structures in asm
    adds a level of abstraction I can do without. This after seeing
    Forth do exactly that and me struggling to remember what conditional
    jump it was actually compiling. OTOH SEQIO.LIB is worth learning
    because it's a mini-application and not just a clever alternate way
    of doing something. YMMV

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr. Emmanuel Roche, France@21:1/5 to All on Wed Nov 10 14:15:18 2021
    "As usual, it started innocently." This must be the understatement of the week.

    An "Old Timer" of the comp.os.cpm Newsgroup, who has not published anything for years, sent me his collection of macros. Unfortunately, they mostly come from the MAC manual.

    However, when browsing them, I had a shock. The statements of the IF-ELSE-ENDM constructs were *INDENTED*! I could not believe my eyes! When I program in high-level languages, I do this automatically, and when I retyped the libraries, I just rewrote them
    in lower case, and did not, for some reason, indent them!

    Since the NCOMPARE library contains at least 6 macros with IF-ELSE-ENDM constructs, indenting them change dramatically the appearance of the library! Ole, you are a genius!

    It is incredible what a well-placed TAB can do.

    Finally, you may have remarked that the comments, at the beginning of Figure 51, says that the program will stop on the "Z" character, while it uses "D"...

    Yours Sincerely,
    Mr. Emmanuel Roche, France

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr. Emmanuel Roche, France@21:1/5 to All on Thu Nov 11 09:59:48 2021
    I think that I have answered the question:

    Anybody knows how to change WRITE so that it does not convert all the strings to upper case?

    if I judge by what the programs say:

    fig42

    Type a character from A to D: e
    Not an A, B, C, or D
    Type a character from A to D: a
    You typed an A
    Type a character from A to D: b
    You typed a B
    Type a character from A to D: c
    You typed a C
    Type a character from A to D: d
    You typed a D
    Bye
    fig44

    Type a character from A to D: e
    Not an A, B, C, or D
    Type a character from A to D: a
    You typed an A
    Type a character from A to D: b
    You typed a B
    Type a character from A to D: c
    You typed a C
    Type a character from A to D: d
    You typed a D
    Bye
    fig46

    Type a character from A to D: e
    Not an A, B, C, or D
    Type a character from A to D: a
    You typed an A
    Type a character from A to D: b
    You typed a B
    Type a character from A to D: c
    You typed a C
    Type a character from A to D: d
    You typed a D
    Bye
    fig48

    Type the stop character: e
    Type a character: a
    You typed an A
    Type a character: b
    Not an A
    Type a character: c
    Not an A
    Type a character: d
    Not an A
    Type a character: e
    Not an A
    Stop character
    Bye
    (...)
    fig51

    Sample control structures
    Type single characters from
    A to D, I will stop on D.
    Type a character: e
    Bad character
    Type a character: a
    You selected case A
    Type a character: b
    You selected case B
    Type a character: c
    You selected case C
    Type a character: d
    You selected case D
    So I am going back.
    That's All, Folks!

    Yours Sincerely,
    Mr. Emmanuel Roche, France

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)