CRCK COM TERM ALX= VOLUME51DOC$ INTRO DOC INTRO DOC-!"#$%&USE DOC '(STAGE2 COM`)*+,-./01234ALXTEST ALX567CK *.* F Check all files and make file of results $sCRCK ver 4.3 - 24K Buffer - 01/17/81 RBS CTL-S pauses, CTL-C aborts :m2F¨CRCKLIST$$$ Check only MYFILE.A+` ^**}|N!"*{z@* K\<7=Ɓo& K] K2h2|2DD~$#~# xK :F°*}p">d<¨ è CANNOT CLOSE CRCFILE$ ++ABORTED++$ *)ALX- DOC89:ALX S2M~;<=>?@ABCDEFGHIJCIO ALXKLMNTERMSUP ASMOPQMEMORY INPRINTERACTS2MSTDEMO S2M UVIOOP SRCWXYZ[\]^_`abcdef CANNOT CLOSE CRCFILE$>CRCKLISTCRC DISK FULL: CRCFIL] w# N!I DONE$!e<ʨ!]K!eKsXXXXXXXX.XXX CRC = \<V++OPEN FAILED++$!"!"*| \\ !~2*" +( DISK FULL: CRCFILE$!"**#"ɯ22!`"!"<¨ ( NO DIR SPACE: CRCFILE$1)ͦp:V++FILE NOT FOUND++$:Ff*}">< CRCK.COM 4.3 01/17/81 RBS!9")1)̀:] Y ++NO FILE NAME SPECIFIED++ To use this program: COMMANDS: CRCK [drive:] [F] Examples: CRCK MYFILE.ASM Check only MYFILE.ASM CRCK *.ASM Check all .ASM files CRIOOP SRCDISKIO2 SRCghijklmnopqrstuvDISKIO2 SRCwDISKIO2-DOC0xyz{|}IOOP$ SUB~#"?(:\> ͇:\̀èV++FILE READ ERROR++$*|):oX|g}o"e n0Ç~͇#~t> ͇> _͛:F{2h2|:!\ K:\2!\ K\ !\ K\!\REV EQU 25H ; 03/19/81 R. CURTISS FOR NEW ALX STRUCTURES ;REV EQU 24H ; 06/17/79 R. CURTISS RFOPEN: ;REV EQU 23H ; 06/17/79 R. CURTISS FINISH RECEIVE FILE CODE ;REV EQU 22H ; 06/14/79 R. CURTISS SABORT, ETAB ;REV EQU 21H ; 06/14/79 R. CURTISS FINI CALL CRLF RET ; ; -------------------------------------------- HELP ; HELP: DB 0DH,0AH,9,'B',9,'SEND BREAK TONE' DB 0DH,0AH,9,'E',9,'SEND CONTROL E' DB 0DH,0AH,9,'H',9,'HELP - LIST COMMANDS' DB 0DH,0AH,9,'Q',9,'QUIT - RETURN TO CP/M' DB 0D ; GET DATA MOV E,A PUSH D CALL CO ; OUTPUT TO CONSOLE POP D LDA RLOG ORA A IF ( NOT ZERO ) ; RLOG = TRUE LHLD MPOINT CALL MEND ; CHECK FOR POINTER AT END OF MEMORY WHEN ( NO CARRY ) ; NOT AT END MOV M,E INX H SHLD MPOINT FIN RETURN TO CP/M DB DREV ; REVISION NUMBER OF DISKIO PACKAGE DB 0,0,0 DB SREV ; REVISION CODE FOR SUPPORT ROUTINES ; ; ----------------------- ; QUIT: DS 1 ; FLAG SET BY COMMAND TO STOP SABORT: DS 1 ; FILE SENDING ABORT FLAG ULTOG: DS 1 ; UPPEN ( 'E' | 'E'-40H ) MVI E,5 CALL MO ; SEND CONTROL E FIN ( 'H' ) LXI H,HELP CALL MSG ; DISPLAY COMMAND LIST FIN ( 'Q' ) MVI A,0FFH STA QUIT ; QUIT = TRUE FIN ( 'O' ) CALL ROPEN ( 'L' ) LDA RFOPEN ORA A IF ( NOT ZERO ) ; RFILE BUFFER LXI H,MSTART ; START OF RECEIVE FILE BUFFER SHLD MPOINT ; RECEIVE FILE POINTER CALL SMODE ; INITIALIZE MODEM INTERFACE XRA A STA QUIT ; QUIT = FALSE STA RLOG ; SAVE = FALSE CMA STA ULTOG ; UPPER/LOWER SWITCH = TRUE REPESH REWRITE ;REV EQU 20H ; 06/13/79 R. CURTISS ALX REWRITE FROM NORDATA1P ;REV EQU 14H ; 10/24/78 R. CURTISS CI & CISTAT DIRECT TO BIOS ;REV EQU 13H ; 10/23/78 R. CURTISS T,U,W BDOS AND BIOS CI ;REV EQU 12H ; 08/09/78 R. CURTISS FIX ERRORS ;RESOLE STATUS IF ( NOT ZERO ) ; DATA READY CALL CI ; GET DATA CPI 'E'-40H ; CONTROL E FOR COMMAND MODE WHEN ( ZERO ) CALL CCP ELSE MOV E,A CALL MO ; SEND CHARACTER FIN FIN RET PROCEDURE CCP CALL CRLF ; NEW LINE MVI E,':' CALL CO ;ELSE MVI E,'@' MOV M,E CALL CO ; WARNING FULL FIN FIN FIN RET PROCEDURE MEND LDA MEMEND+1 SUB H RC ; RETURN IF FULL RNZ ; RETURN IF NOT FULL CY=0 LDA MEMEND SUB L ; CY=1 IF FULL RET PROCEDURE CONCHK CALL CISTAT ; GET CONR/LOWER CASE SWITCH FLAG RFOPEN: DS 1 ; RECEIVE FILE OPEN FLAG RLOG: DS 1 ; RECEIVE DATA SAVE FLAG MSTART EQU 1000H ; START OF RLOG AREA POINT: DS 2 ; TEMPORARY POINTER FOR WRITE TO DISK MPOINT: DS 2 ; POINTER FOR RLOG STORAGE MEMEND: DS 2 ; POINTER ECEIVE FILE OPEN MVI A,0FFH STA RLOG ; RLOG = TRUE FIN FIN ( 'N' ) XRA A STA RLOG ; RLOG = FALSE FIN ( 'C' ) CALL RCLOSE ( 'S' ) CALL SEND ( 'U' ) LDA ULTOG CMA STA ULTOG FIN ( OTHERWISE ) MVI E,'?' CALL CO FIN FINAT CALL RCVCHK ; CHECK FOR RECEIVE DATA CALL CONCHK ; CHECK FOR CONSOLE DATA LDA QUIT ORA A UNTIL ( NOT ZERO ) ; QUIT = TRUE JMP EXIT ; RETURN TO CP/M PROCEDURE RCVCHK CALL MISTAT ; GET RECEIVE STATUS IF ( NOT ZERO ) ; DATA READY CALL MIV EQU 11H ; 08/09/78 R. CURTISS MORE CODE ;REV EQU 10H ; 07/26/78 R. CURTISS INITIAL CODING ; ; ; NORDATA TERMINAL PROGRAM WITH FILE TRANSFER (SEND AND RECEIVE) ; ; ORG 100H JMP START DB REV ; REVISION NUMBER IN CODE EXIT: JMP 0000H ; PROMPT TO CONSOLE CALL CIE ; GET COMMAND CHARACTER FROM CONSOLE PUSH PSW CALL BLK ; SPACE TO CONSOLE POP PSW SELECT ( 'B' ) CALL BRK ; SEND BREAK TONE MVI A,10 CALL DELAY ; DELAY FOR 1 SEC CALL SMODE ; INITIALIZE MODEM INTERFACE FIRITE ACCESS CODE DELETE OLD FILE ACCE: DB 1 ; READ ACCESS CODE FTAB: DB 0,0,0,'R' DS 33 ; FILE CONTROL BLOCK DS 128 ; DATA BUFFER DS 40 ; STACK SPACE STACK: PROCEDURE START LXI SP,STACK LHLD BDOS+1 DCR H SHLD MEMEND ; END OF RECEIVE TO END OF RLOG AREA BUFSIZ EQU 20 ; CONSOLE READ BUFFER SIZE CBUFF: DB BUFSIZ ; BUFFER MAX SIZE DB 0 ; CURRENT SIZE DS BUFSIZ ; CONSOLE BUFFER TAB: DB 0 ; TAB COLUMN COUNTER XDATA: DS 1 ; TEMPORY STORAGE FOR READ/WRITE DATA WACCE: DB 3 ; WH,0AH,9,'O',9,'OPEN RECEIVE FILE' DB 0DH,0AH,9,'L',9,'LOG RECEIVE DATA' DB 0DH,0AH,9,'N',9,'NO LOG RECEIVE DATA' DB 0DH,0AH,9,'C',9,'CLOSE RECEIVE FILE' DB 0DH,0AH,9,'S',9,'SEND FILE' DB 0DH,0AH,9,'U',9,'UPPER/LOWER CASE SWITCH' DB 0 ; END OF M GET CHARACTER AND IGNORE FIN FIN FIN RET PROCEDURE HCHECK CALL MISTAT ; CHECK RECEIVE STATUS IF ( NOT ZERO ) ; DATA READY CALL MI ; GET CHARACTER CPI 'S'-40H ; X-OFF WHEN ( ZERO ) CALL MI ; WAIT FOR ANOTHER RECEIVE CHARACTER CPI 'Q'ELETE ( OTHERWISE ) CPI 20H IF ( CARRY ) ; CONTROL CHARACTER PUSH PSW MVI E,'^' CALL MOUT ; SEND UP ARROW POP PSW ADI 40H ; CHANGE TO NON CONTROL MOV E,A FIN CALL MOUT ; SEND CHARACTER CALL CTAB ; TAKE CARE OF COUNTER FOR TAB EXPANSB D BREAK IF ( NO CARRY ) ; POINT >= MPOINT done MOV A,M STA XDATA INX H SHLD POINT LXI H,FTAB LXI D,XDATA CALL BWRITE ; WRITE NEXT BYTE TO DISK ORA A BREAK IF ( NOT ZERO ) ; WRITE ERROR FIN LXI H,FTAB CALL DCLOSE XRA ACHECK ; CHECK HOST FOR DATA OR PAUSE (X-OFF) CALL MOSTAT ; CHECK MODEM OUT STATUS UNTIL ( NOT ZERO ) ; SEND READY POP D CALL MO ; SEND THE CHARACTER RET PROCEDURE KCHECK CALL CISTAT ; CHECK CONSOLE STATUS IF ( NOT ZERO ) ; DATA READY CALESSAGE PROCEDURE SEND LXI B,ACCE CALL OPENF ; OPEN FILE FOR READ IF ( ZERO ) ; NO OPEN ERROR XRA A STA SABORT ; SEND ABORT = FALSE STA TAB ; INIT TAB COLUMN COUNTER CALL SREAD ; READ FIRST CHARACTER FROM FILE WHILE ( ZERO ) ; NO ERROR OR OPENF ; OPEN FILE FOR WRITE RNZ ; RETURN IF ERROR MVI A,0FFH STA RFOPEN ; RECEIVE FILE OPEN = TRUE STA RLOG ; RLOG = TRUE LXI H,MSTART ; START OF RECEIVE FILE BUFFER SHLD MPOINT ; RECEIVE FILE BUFFER POINTER RET PROCEDURE RCLOSE LXI-40H ; X-ON WHILE ( NOT ZERO ) ; NOT X-ON MOV E,A CALL CO ; DISPLAY CHARACTER CALL MI ; WAIT FOR NEXT CHARACTER CPI 'Q'-40H ; X-ON FIN FIN ELSE MOV E,A CALL CO ; DISPLAY CHARACTER FIN FIN RET PROCEDURE ROPEN LXI B,WACCE CALLION FIN FIN CALL SREAD ; READ NEXT CHARACTER FROM FILE FIN MVI A,10 CALL DELAY ; DELAY FOR 1 SECOND LXI H,FTAB CALL DCLOSE ; CLOSE FILE MVI E,1AH CALL MOUT ; SEND CONTROL Z FIN RET PROCEDURE ETAB LDA TAB DCR A ANI 7 INR A STA RFOPEN ; RECEIVE FILE OPEN = FALSE STA RLOG ; RLOG = FALSE RET ; ; END-OF-FILE  CALL BWRITE ; WRITE NEXT BYTE TO DISK ORA A BREAK IF ( NOT ZERO ) ; WRITE ERROR FIN LXI H,FTAB CALL DCLOSE XRA AL CI ; GET KEYBOARD CHARACTER SELECT ( 1AH ) MVI A,0FFH STA SABORT ; SEND ABORT = TRUE FIN ( 'S'-40H ) REPEAT CALL HCHECK ; CHECK FOR INCOMING DATA CALL CISTAT ; CHECK CONSOLE STATUS UNTIL ( NOT ZERO ) ; ANY KEY TO CONTINUE CALL CI ; EOF LDA XDATA ; GET CHARACTER ANI 7FH MOV E,A SELECT ( 9 ) CALL ETAB ; EXPAND TAB ( 0DH ) ; CARRIAGE RETURN CALL MOUT ; SEND CARRIAGE RETURN XRA A STA TAB ; INITIAL TAB COLUMN COUNTER FIN ( 0 | 0AH | 7FH ) NOP ; IGNORE NULL, LF, D H,MSTART SHLD POINT LDA RFOPEN ORA A RZ ; RETURN IF RECEIVE FILE NOT OPEN LOOP LHLD MPOINT XCHG ; DE = MPOINT end of received data storage LHLD POINT ; HL = POINT temp pointer for writing to disk MOV A,L SUB E MOV A,H SBB LXI D,XDATA CALL BREAD ; READ NEXT BYTE ORA A IF ( ZERO ) ; NO ERROR OR EOF LDA XDATA SUI 'Z'-40H ; CONTROL Z SUI 1 SBB A FIN FIN RET PROCEDURE MOUT PUSH D REPEAT CALL KCHECK ; CHECK KEYBOARD FOR ABORT OR LOCAL PAUSE CALL H MOV D,A MVI E,' ' REPEAT PUSH D CALL MOUT ; SEND SPACE POP D DCR D UNTIL ( ZERO ) XRA A STA TAB RET PROCEDURE CTAB LDA TAB DCR A ANI 7 STA TAB RET PROCEDURE SREAD LDA SABORT ORA A IF ( ZERO ) ; NOT ABORT LXI H,FTASTAGE2 IS: STAGE2 is a versatile macro processor developed by William M. Waite. Operating on a generalized pattern recognition principle, it can be used for language translation, textual data filtering, limited printer output formatting, batch fis is to be used while reading the INTRO.DOC file. IMPLEMENTATION FILES: IOOP.SRC Initialization and input/output package DISKIO2.SRC General CP/M disk input/output package DISKIO2-.DOC Documentation for above IOOP$.SUB Submit file for 8 bits (only two used) Since the value field is sometimes used to hold string length, strings are limited to 255 characters maximum. Under some circumstances the value field is considered to be signed so that strings longer than 127 charactersome applications are an order of magnitude simpler to implement with STAGE2 than with conventional algorithmic languages. WEAK POINTS: A bit slow Uses lots of memory for large applications (language translation) Macro code is very cryptic in aS: ALX.S2M Assembly Language eXtension translator macros ALX-.DOC Notes on ALX.MAC ALXTEST.ALX Test case for the ALX macros TERM.ALX Sample program (incomplete) VDB.ALX TDL video display driver for H19 emulation CIO.ALX CP/M console I/O iage return terminates Line feeds are ignored Nulls are ignored Deletes are ignored Output lines Carriage return and line feed on every line Channel 5 implemented for console input and output IMPLEMENTATION LIMITATIONS: STAGile editing and other text processing applications. FEATURES: Pattern matching Symbol table (storage and retrieval under user control) Symbol generator Integer arithmetic Arithmetic expression evaluator Scan controlled iteration (search character stored by STAGE2 takes 1 FLUB word or 4 bytes in this implementation. CP/M VERSION AVAILABILITY: CP/M Users' Group 1651 Third Avenue New York, NY 10028 DISCLAIMER: )()!&(%$#"#"%!!$(%!##!(!$!!$=(00(!#=!! so there! Use it a may cause strange results, but NOT a crash. STAGE2 seems to be extremely well protected against crashes. Since the pointer field is used for arithmetic operations, values are limited to the range -32767 to 32767. -32768 causes trouble. Eachppearance REFERENCES: STAGE2 is in the public domain and is documented by the author in the book: Implementing Software for Non-numeric Applications by W. M. Waite 1973 Prentice Hall Chapter 9 and appendix A include STAGE2 user inforwith PMMI modem in "parallel" MEMORY.INP Macros and source for memory demonstration INTERACT.S2M Macros to demonstrate interactive use of STAGE2 DEMO.S2M Macros for interactive exercise of most conversions and a few processor functions. ThE2 is modeled on an abstract machine called the FLUB machine. FLUB stands for First Language Under Bootstrap. The FLUB machine word is made up of three fields: Pointer field 16 bits in this CP/M implementation Value field 8 bits Flag fieldfor specific characters) Count controlled iteration Conditional and unconditional branching (skips) I/O channel control Limited output formatting Recursion Error traceback showing all macro calls STRONG POINTS: Highly transportable St your own risk. MORE INFORMATION: HELP.DOC For the STAGE2 novice - start here USE.DOC STAGE2 I/O summary and command line specification INTRO.DOC Introduction to the STAGE2 processor IMPL.DOC STAGE2 implementation notes EXAMPLE FILEby: Dick Curtiss 843 NW 54th Seattle, Washington 98107 (206) 784-8018 and is in the public domain. DEVIATIONS FROM THE VERSION DISTRIBUTED BY WAITE: Variable length lines for input and output (132 char max) Input lines Carrmation, source listings and implementation directions. STAGE2 is also documented by the author in: "Communications of the ACM" Volume 13 / Number 7 July 1970 Pages 415-421 STAGE2 for CP/M: This 8080 implementation was accomplished creating IOOP.HEX FLT1.FLB FLUB translation test program 1 FLD1.DAT Test data for FLT1 FLT2.FLB FLUB translation test program 2 FLD2.DAT Test data for FLT2 STG2.FLB Source program for STAGE2 ST2T.DAT Test data for STAGE2 FLUB8080.S2Mrsive macro call to parse rest of line % ------------------------- end of macro STATEMENT $;$# To recognize and split statement with comment PROCESS !10% macro call to process single statement % ------------------------- end of macro STATEM macros designed to generate a sequence of assembler language instructions which evaluate the conditional expression. Then a "jump if false" instruction would be generated to branch to the loop exit label. Next, the remainder of the line would bTATEMENT !30% macro call to parse remainder of line JUMP LOOP!F13% output loop jump EXIT:!F13% output loop exit label % ------------------------- end of macro CONDITION $<$# To recognize less than compare LOAD !10!F13% output loE PROBLEM: Suppose it is desired to recognize the following WHILE statement and translate it into assembler type language. WHILE ( X < Y ) PRINT X*Y : X = X + 1 ; Comment A top level macro would be used to recognize the "WHILE" as a keyword. STAGE2 macros for translating FLUB into 8080 code STG2SUP.ASM Support routines for the FLUB machine STG2MATH.ASM 16 bit math routines for the FLUB machine FLUB$.SUB Submit file for assembling FLT1, FLT2 or STG2 branch to the looping label. Finally, "WHILE" statement processing is completed by generating a loop exit label. EXAMPLE MACRO EXPANSION: LOOP: LOAD X CMP-LT Y J-FALSE EXIT LOAD X MULTIPLY Y CALL PRINT-RESULT LOAD X e passed on to macros designed to recursively break apart multiple statement lines and process each single statement with still other specialized macros. After decomposition of the "WHILE" statement is complete, a jump instruction is generated to STAGE2 INTRODUCTION COPYRIGHT: Written: 06/15/79 Updated: 06/17/79 This introductory material is the property of: Dick Curtiss 843 NW 54th Seattle, Washington 98107 Permission is granted to copy for personal use only. Thisad X instruction CMP-LT !20!F13% output compare Y instruction % ------------------------- end of macro STATEMENT $:$# To recognize and split multiple statement PROCESS !10% macro call to process single statement STATEMENT !20% recu As part of the recognition process the statement would be broken into three parts, "WHILE", "X < Y", and the rest of the line. The first step in the translation process is to generate a looping label. Next, "X < Y" would be passed on to a set of ADD #1 STORE X JUMP LOOP EXIT: EXAMPLE MACROS: WHILE$($)$# To recognize WHILE statement LOOP:!F13% output looping label CONDITION !20% macro call to parse conditional expression J-FALSE EXIT!F13% output exit jump SE2 forces a top down approach to problem solving using stepwise refinement and recursive descent. Expect to read this material several times before it sinks in. The best way to learn STAGE2 is to study examples and experiment. Good luck! EXAMPL material may NOT be used for publication without written permission of the author. STAGE2 PROGRAMMING TECHNIQUE: STAGE2 is unlike conventional languages and requires getting used to a different way of approaching a problem. By its nature, STAGENT $# To recognize single statement PROCESS !10% macro call to process single statement % ------------------------- end of macro PROCESS PRINT$# To recognize and process PRINT statement *** macro code not shown % ------------------------ersion "0" copies the parameter string unchanged to the constructed line. The constructed line can be thought of as a scratch string which is empty at the start of a code body line scan. In summary the three characters "!10" instruct STAGE2 to apin the example instructs STAGE2 to store parameter string 2 into the memory using parameter string 1 for access to memory. In other words the string in parameter 1 is given a value in memory and that value is the string in parameter 2. Paramet body line end character. An empty code body line (macro terminator) has the code body line end character in column 1. A special escape character is used in code body lines for parameter reference and invocation of processor functions. Charac used to print information stored in the memory. PRINT MEM[$]# 4. Template line !10=!11!F14% 5. Extract info and output % 6. End of macro The template in line 4 contains 1 parameter flag which represents the string which will be usedharacters in the order shown in the template line. The parameter flag characters, "$", will match any balanced strings including a null string. A balanced string is one containing equal numbers of left and right bracketing characters, usually "("- end of macro PROCESS $=$# To recognize and process assignment stmt. *** macro code not shown % ------------------------- end of macro READING MACROS: Macros consist of a template line followed by one or more code body lines. The macro is minator. Strings for a successful match: MEM[25]=TWENTY FIVE# Parameter 1 = "25" Parameter 2 = "TWENTY FIVE" Parameters 3-9 = "" MEM[ABC]=HELLO# P1 = "ABC" P2 = "HELLO" MEM[EQUATION]=A=2*(B+C)# P1 = "EQUATION" Per 1 is the string segment represented by the first "$" in the template and parameter 2 is the string segment represented by the second "$" in the template. The maximum number of parameters is nine. Line 3 is an empty code body line or macro terters in a line following the special end characters are taken as comment only. SPECIAL CHARACTERS: # Template end of line $ Template parameter flag % Code body end of line ! Code body escape ( Left bracket ) Right bracket These s to access the memory. The first escape character in line 5 is followed by a non-zero digit, "1", which is taken to be a reference to parameter string 1. The digit, "0", following the parameter reference is a conversion code (0-8 allowed). Conv and ")". Line 2 contains a processor function request. The escape character "!" folowed by "F" followed by a digit specifies one of ten possible functions. The "F" can actually be any non- numeric or special character. The function "3" shown terminated by an empty code body line. Macro templates, which are terminated by a special template end character, consist of character strings with special parameter flag characters interspersed. Code body lines are terminated by a special code2 = "A=2*(B+C)" MEM[X=Y]=Z# P1 = "X=Y" P2 = "Z" Strings for a match failure: MM[12]="E" MISSING# MEM [XYZ]=SPACE AFTER "MEM"# MEM[ABC)]=UNBALANCED STRING# MEM[ABC]=UNBALANCED (STRING# MACRO EXAMPLE: This macro may bebuilt in memory. MEM[$]=$# 1. Template line !F3% 2. Store into memory % 3. End of macro The template in line 1 contains two parameter flags (maximum of nine allowed). For a string to match the template it must contain the literal cpecial characters are user selectable on the first line of input to STAGE2. The particular characters shown above were arbitrarily chosen for the examples which follow. MACRO EXAMPLE: This macro may be used to store information into the STAGE2 pend parameter 1 to the constructed line. The next character in line 5 is a literal "=" which is appended to the constructed line. Next is another escape character followed by the digit "1". This is another reference to parameter string 1. TLANCED STRING# MEM[ABC]=UNBALANCED (STRING# PRINT MEM[25]# PRINT MEM[ABC]# PRINT MEM[PDQ]# FORMAT MEM[25]# FORMAT MEM[ABC]# FORMAT MEM[PDQ]# END# Note: The "#" shown at the end of the input lines are optional in the CP/M immory using parameter 1 for access. The output request in line 9 is like that of line 5 except that the constructed line is empty (null). This condition instructs STAGE2 to use the following code body line as a formatting template which should noifies the output function. The following digit, "4", specifies the output channel. "!F14" causes output of the constructed line to channel 4. When the channel number is ommitted output is to channel 3 by default. Processing of line 5 is now com PRINT MEM[$]# 4. Template line !10=!11!F14% 5. Extract info and output % 6. End of macro FORMAT MEM[$]# 7. Template line !11!26% 8. Extract info !F14% 9. Output 1111111= 22222222222222222% 10. Format % 11. End of ine into the specified parameter. This also results in clearing the constructed line to null. Processing of line 8 is complete as the end of line character comes next. It is possible, however, to have more operations appear in that same code bodyhis time, however, the conversion digit is a "1" which instructs STAGE2 to append information from the memory to the constructed line using the specified parameter string for access. At this point 3 items have been appended to the constructed linding blanks are not suppressed) and blank filled or truncated on the right depending on parameter length and field width. Strings for successful match: FORMAT MEM[25]# Ch4 = "25 = TWENTY FIVE " FORMAT MEM[ABC]# Ch4 = "ABC t be confused with macro templates. Fields of numeric characters refer to corresponding parameter strings. Non-numerics in the formatting template appear in the output line as is. Parameter strings are inserted into the fields left justified (leaplete and line 6 terminates the macro. Strings for successful match: PRINT MEM[25]# Channel 4 output = "25=TWENTY FIVE" PRINT MEM[ABC]# Ch4 = "ABC=HELLO" PRINT MEM[PDQ]# Ch4 = "PDQ=" nothing stored previously MACRO Emacro END# 12. Template line !F0% 13. Terminate processing %% 14. End of macros MEM[25]=TWENTY FIVE# MEM[ABC]=HELLO# MEM[EQUATION]=A=2*(B+C)# MEM[X=Y]=Z# MM[12]="E" MISSING# MEM [XYZ]=SPACE AFTER "MEM"# MEM[ABC)]=UNBA line (i.e. "!11!26 !F14#"). The character after the 6 in this alternative is ignored so a space is shown. At this point parameter 1 still has the string resulting from the template match and parameter 2 contains the string extracted from the mee: parameter string 1, "=", and a string from the memory. The next character in line 5 is another escape. This time, however, the following character is non-numeric indicating a processor function request. The next character, the digit "1", spec = HELLO " FORMAT MEM[PDQ]# Ch4 = "PDQ = " EXAMPLE RUN: FILE "MEMORY.INP" #$%!0 (+-*/) 0. Special character selection MEM[$]=$# 1. Template line !F3% 2. Store into memory % 3. End of macro As in line 5, the "!11" in line 8 appends information from the memory to the constructed line using parameter 1 for access. Then "!2" is a reference to parameter 2. The following conversion digit, "6", instructs STAGE2 to copy the constructed lXAMPLE: This macro will also display information stored in the memory but formatted into fields. FORMAT MEM[$]# 7. Template line !11!26% 8. Extract info !F14% 9. Output 1111111= 22222222222222222% 10. Format % 11. End of macro plementation as carriage return is sufficient for an end of line condition. The special character when used is the same terminator used for macro template end of line. It can be used if it is desired to allow comment information in theopied into the specified parameter. The scanned string and break character are deleted from the CL. Break characters enclosed in brackets will not be recognized as the scanned string would not be balanced. After scanning stops code body lines undefined symbol is treated as zero. If null, P1 will be treated as zero. A symbol with a non-numeric value will cause an error message and traceback. !15 Append LEN(P1) to the CL ; Append a string of digits to the CL to represent the lessions and balanced strings) 8 Addition operator 9 Subtraction operator 10 Multiplication operator 11 Division operator 12 Closing bracket (to match #7) PARAMETER CONVERSIONS: There are a maximum of ten parameters, numbpply new values for the parameter. The original value will will be restored after exit from the loop. The CL is scanned for break characters which are specified following the digit "7". All of the characters up to the end of line character) = S1 ; define from symbol generator S1 = S1 + 1 ; increment symbol generator Append MEM(P1) fin ( otherwise ) Append MEM(P1) to the CL fin !13 Useful only in conjunction with context-controlled iteration. (Described a source input stream. COMMAND LINES: STAGE2 CH3,CH4=MEMORY.INP TYPE CH3 TYPE CH4 FLAG LINE: The first line read by STAGE2 is used to specify the user's special symbol selections. column description 1 End of template and sourcewing "!16" will be ignored. If it is the end of code body line character processing will continue on the following line. Otherwise, processing will continue with the next character. When used inside of an iteration loop the string placed in ength of the parameter string. A null string results in a single zero digit. !16 P1 = CL, CL = null ; Copies the CL into parameter 1, replacing whatever might have been there before. Also, the CL is cleared. The character immediately folloered 0 through 9. Parameter 0 is a special case. There are nine possible parameter conversions, numbered 0 through 8. Most of this discussion will refer to specific parameters but the remarks apply generally to parameters 1 through 9. !10 Appe will be used as break characters. If no break characters are specified the CL scan is broken on each character. When a break character or the end of the CL is reached scanning stops and the scanned string (excluding the break character) is cfter !17) !14 Append EVAL(P1) ; Evaluate the parameter string as an arithmetic expression and append a string of digits to the CL to represent the result. Non-numeric items in the expression will be taken as symbols for memory reference. An input lines 2 Template parameter flag 3 End of code body line 4 Escape character for code body (parameter or function ref.) 5 The character for zero 6 Space character for formatted output 7 Open bracket (arithmetic exprthe specified parameter is not retained from one iteration to the next or after exit from the loop. !17 This starts a context controlled iteration loop. The current value of the specified parameter is saved as the iteration process will suundefined ) Append null to the CL ( otherwise ) Append MEM(P1) to the CL fin !12 Similar to conversion 1 except when P1 is undefined. CASE ( P1 = null ) Generate error message and trace back ( P1 undefined ) MEM(P1nd parameter string 1 to the constructed line. !20 Append P2 to the CL. !11 Append MEM(P1) to the CL. Using P1 for access, append the value of the symbol to the CL. CASE ( P1 = null ) Generate error mesage and trace back ( P1 are expanded within the loop which ends at an "!F8". After all lines within the loop have been processed, scanning of the CL continues unless the CL is null. When the CL is null the iteration loop is terminated. !F8 Processor function to de51 IF ( P1 <> P2 ) SKIP = EVAL(P3) !F6 Set skip counter based on the relative values of 2 arithmetic expressions. The test condition is specified by a character following "!F6". !F6- IF ( P1 < P2 ) SKIP = EVAL(P3) !F60 IF ( P1 If P1 is null no copying takes place. Copying continues up to an input line whose initial substring matches P1. The line which matches P1 is ignored, copying stops and the input channel is positioned to the line following the matched line. NERATOR: !0 Parameter "0" is a reference to an internal symbol generator. Within a given macro expansion up to ten unique symbols (actually integers or strings of digits) are available; "!00" through "!09". After the macro expansion is complcounter unconditionally. The skip counter applies to macro code body lines. The skip feature allows conditional expansion of portions of a macro code body. Parameter string 1 is evaluated as an arithmetic expression (see conversion 4 descrips of identical digits. "22222" is a five character field into which parameter string 2 will be inserted, left justified with blank fill or truncation on the right as required. A given parameter may be referenced for more than one field in thefine the scope of an iteration loop. !13 Append BREAK(P1) to the CL ; The break character is the single character immediately following the specified parameter which represents a substring of the line being scanned. When the end of line is copy to the specified channel fin ELSE copy to channel 3 5!F2 CI = 5 , out is 3 2R!F2 CI = 2 , Rewind 2 , out is 3 !F24 CI unchanged , out is 4 2!F23R CI = 2 , out is 3 , Rewind 3 before copy In all cases no copy If no match line is found end of file terminates the copy. WHEN ( input channel specified ) make it the new current input (CI) channel fin ELSE the current input channel number is unchanged WHEN ( output channel specified ) ete the symbol generator is incremented so that future macro expansions will get different symbols. PROCESSOR FUNCTIONS: There are eleven processor functions, numbered 0 through 9 and E. Some processor functions assume use of specific parametion) and the result is placed in the skip counter. SKIP = EVAL(P1) !F5 Set skip counter based on string compare for equality. The test condition is specified by a character following "!F5". !F50 IF ( P1 == P2 ) SKIP = EVAL(P3) !F formatted line. !F14 Output the CL to channel 4. !F1 Output to channel 3 as default channel. !F12R Output to channel 2 after rewind. !F2 Change I/O channels and copy text from the specified input channel to the specified output channel. reached, the break character is null. !18 Append a string of digits to the CL to represent the internal storage code for the character in P1. Unless P1 contains exactly one character an error message and traceback will result. SYMBOL GEtakes place if P1 is null. !F3 MEM(P1) = P2 ; Using parameter string 1 for access, store parameter string 2 into memory. (i.e. the value of P1 is defined to be P2). If P1 is null an error message and traceback result. !F4 Set the skip output. A format line specifies exactly the number of characters in the line to be output. Non-numeric characters in the format specification are output exactly as they are. Parameter fields in the format specification are denoted by stringters. !F0 Terminate processing. !F1 Output request. The output request must appear at the end of a code body line. The CL is output if it is not null. If it is null the following code body line will be used as a format specification for == P2 ) SKIP = EVAL(P3) !F61 IF ( P1 <> P2 ) SKIP = EVAL(P3) !F6+ IF ( P1 > P2 ) SKIP = EVAL(P3) !F7 Count-controlled iteration. The CL is evaluated as an arithmetic expression (see conversion 4 description) and the resulting vadevices disk disk disk disk CON: CON: CON: CON: LST: LST: NUL: NUL: default error disk CON: LST: CON: channel 2 file name is fixed STAGE2.CH2 channel 5 is always the console additional device names accepted CON: put as can be seen in the above program. Output, however, is under user control through macro body processing. If STAGE2 fails to match an input line against a macro template the line will be output to channel 3 as is and the processor will go on r message and traceback. All macro calls to the current level will be output in reverse order to channel 4. The last traceback line is the current input line. ----------------------------------------------------------------------- STAGE2 PROGRt/output console channel (for interactive use) 6-9 not implemented could be made additional scratch and/or punch & reader devices COMMAND LINE FORMAT: [[,]=][,[, ... ]] concatenation allowed on structure for the template matching algorithm} INPUT_NEXT_LINE {gets first source line from input file (channel 1) - this is the first line following the last macro} WHILE NOT END_OF_FILE DO BEGIN MATCH ( Llue is placed in an iteration counter. The loop, which ends at an "!F8", is repeated with the iteration counter decremented for each iteration. The loop terminates when the counter reaches zero. !F8 Defines the scope of count-controlled loop to the next input line. ails to match an input line against a macro template the line will be output to channel 3 as is and the processor will go on AM: This is a highly simplified description of the STAGE2 algorithm. PROGRAM; PROCEDURE MATCH ( STRING ); BEGIN attempt to match STRING against macro templates IF MATCH_SUCCESSFUL THEN FOR each line of macro code bodchannel 1 [ ] optional items examples: STAGE2 ALXTEST.ASM,LST:=ALX.S2M,ALXTEST.ALX STAGE2 TERM.ASM,TERM.LST=ALX.S2M,TERM.ALX STAGE2 DEMO.S2M STAGE2 CH3,CH4=MEMORY.INP STAGE2 INTERACT.S2M CHANNEL 1 2 3 4 5 valid INE ); {attempt to match the line against all macro templates} INPUT_NEXT_LINE END; END. Except for switching channels or rewinding channels, the STAGE2 user has no control over input. The processor has a built in loop for ins and context- controlled loops. Loop nesting is permitted. Skipping out of loops is permitted. Skipping over entire loops is tricky business (see Waite's book, page 398). !F9 Terminates expansion of the current macro. !FE Force an erroINPUT/OUTPUT CHANNELS: channel 0 output bit bucket channel 1 input normal input channel (macros & text) 2 input/output scratch channel 3 output default output channel 4 output second output channel (usually printer) 5 inpu-- program starts here ------------ } INPUT_FLAG_LINE {gets special character definitions from the first line input from channel 1} INPUT_MACROS {reads macro code bodies into memory from channel 1 and builds templates into tree y DO BEGIN scan code body line and perform operations IF CONSTRUCTED_LINE <> NULL THEN MATCH ( CONSTRUCTED_LINE ); {note recursive call} END ELSE output STRING to channel 3 END; BEGIN { --------------= KBD: = TTY: = CRT: LST: = LPT: Note: Tabs are NOT expanded for the list device (sorry about that).  channel 2 file name is fixed STAGE2.CH2 channel 5 is always the console additional device names accepted CON: #6    >?=_.,:;<> 3 *b *b %*b #>w=&o23  ~#~# :g =2g "b "| ! "e `i^#VNy2 #^#V" *b ~U #~U #"~ l Y ͗ M : * w ] ] *~ ͼ : l l l ʓ ʕ > *| w#"| "b "e 6~U #~U #~_<w{ U ] *b %~*e w] I = *LDF!E^#!EN# ~'wa{ !F=͙P!F""!:"&!?"(s6#""!F"&,͙m!?"(s6#"(*"ʖʖ*&*(~ȷʤ#Ù<ʰ:=_!"^#V>*c~+ O###>:*STAGE2.CH2NUL:CON:LST: >>>>> COMMAND ERROR - REENTER $$"b ~U 2d *b  4PÜ$Ô×1Pbͱ Pv!_w#j*%2}"~x2="!d~G:}:x!b~ͫ!d6:}>>x==2b #>w"b ~U #~U # O 0 GQ   Q  Q "b G~U #~U #~_<w#p>] o U ] I = *b #>w3 @G:ʪ 6ì p .¿  #6 ¿ #6  #~?  x  #* 6? w  =!cqyNULCONTTYCRTKBDLSTLPT~,~=~ #+x_  3}1 U :d =5  2d = + U = U = U = U *b $6 *b :d w#w#w] "b ~q ͙ z z U ] U *b Nw#w#w ] = U ] ##~/Ɓ6+=¦ o :g !h ^#VZ ñ :g <2g =_!h *b s#r*b !h :g O  ~#G~# T]͘>!`F++6? X=?=Z=y>*~:ZBK >+N m#^R] R R+N ʌ#^X| X Xͦ>!d6Z >ɯ*!c~*~:=_!~#fo!E:+"+" ʃF R*~~ʪ:=>*",͙>#""=Z *" *l#"l*l"``*ͪ*+"*ͤ:2*ͪ*l"t*t"*"**t":2:2*"t:[<2[*0#"0*0ͪ**t<*0ͤ*0+"0:[=2[:!S2*4+"*4ͪ*"4:[!‘*ͤ:=2:!o:!*4+"*+"*ͪ*+"*ͪ*+"*ͪ*+"*ͪ*+"*ͪ*+"*"4*4*0q0*@ͤ*ͤ:2*@"!"D(:F!&:!t(*4ͪ*\*4"4d*4ͪ*\*4"d*4+"4H*4ͪ*4+"4L*4ͪ*4+"4h*4ͪ   *** I/O ERROR ****** EXPRESSION ERROR ****** CONVERSION ERROR ****** MEMO=2:!*`ͤ*4+"``*4ͪ*`"4*4*0q0:=2:2F*Tͤ*T"!c"D(:2F*ͤ:!*0":2*l#"l*l"*4#":2*"*"**":2*"*+"*ͪ:<2**0q0**¢*2b:b!‡02C*0"@`*@ͪ:2F2G2K*4"H2O2S:So/G>!3"+!2^#"-63}22*+~#"+*- Gͤ*#":!S2*0#"*0ͪ*"0**4*0ͪ*0#"0*4*0q0*ͪ*ͤ:2b!|"|,**t<*4+"x*x*0q0x*4ͪ*x"4*t*"t<*ͤ:!*+":!c¼*"t<*\*"*d*‡0*H"`:2*H"**p/*p+"p*`"42c*4+"`*`*0q0`*4ͪ:c!o:c!Cʏ:<2:c!G/*`"DD*4ͪ/*`"42c*4+"``*4ͪ*`*0q0:c!o*4+"*ͪ*+"*ͪ*+"*ͪ*+"*#:!*ͤ:c!:c!ʝ:c!E:c!#s*":c!:o/zU =))Oʹʹ̀͸ø̀"!6{_zW5>)D*OxGҪ !?Ì||/g}/o#2IDSCMF!N#D:'!#2&n:2b:2c*"`:c p#"-6"->G>!3"-G>#3332}o|g|}|||}ʹT])))øʹ͸ø**0q0*4ͪ*"4l*4ͪ*h#"h*4*H"*":2:2*H"*ͪ*4+"H:*d"**`ʼ:c!7ʀ*#"*h#"h:c!:c!:c!a :c!##:c!'ʣ!:c!+E":c!/1#:c!3ʉ%:c!:#!#2"!"DD*4"x:2*"*":!/,*"t*|:s2:!ʯ/*ͤ*":2:!s‹,*4ͪ*4+"4*4*0q0:=2*"/,:!w,:!{,:!,:!,:!,:<2*ͤ:!‹,:2:<2:2g*"t:!2:=2ͤ!&"DT&* *"*ͤ* *"**0q0*ͤ*ͪ::!1):2:=2:2*#"*ͪ*#"*ͪ*D:!ʡ#*#"*ͤ*#"*ͤ*ͪ*#"*Hͤ*#"*ͤ::2:o2*0+"0":c2b:b!::b!‡0:!::=2*ͤ2:!! :2:!Ç0*ͤ:!:!:*ͤ:2F*Tͤ*T"! "D(:2F:2*"*"*#"*ͤ:!*":2:2:!N!*ͪ:!*0q0*ͪ:2*ͪ:2(:2*#"*ͪ*#":2:2*"*ͪ1):!+:!+*ͤ:<2:=2*":!s*:2:<2:!+*ͤ:=2*":<2:!sʧ*:!®*:=2:!®**"*":2:2*H"*4+"4:2F*"D:2:2*,":2:2*"*4+":<2*4ͪ*4+"4*4ͪ*4+"4D*4ͪ*4+"4*h#"h*h`ͤ*4*"``*4ͪ*4"*4+"4*4*0q0:b!]$D*4ͪ:2F*4"*4+"4:s2/*hͤ:2:!R*h#"h:!S2*hͤ:!R:ͻ2*h#"h:c!ʏl*4ͪ*H"*4*H€(*h#"h*h`ͤ:b!œ*h+"h:co/B BRANCH ( V1 ) L1 CPI V1 JZ L1 ( V2 | V3 | V4 ) L2 CPI V2 JZ L2 CPI V3 JZ L2 CPI V4 JZ L2 -------------------------------------- `~ ;To accept an input line starting with tab .TRIM `10~ ; remove leading spaces or tabs ^IND`76 ^TRIM`86~ ; indentation an line reference >> `71`81~ ; output to listing channel .STM `81~ ; ------------- Statement is allowed if top of stack is one of the following: I,K,L,O,R,W,*. Otherwise particular control statements are expected. I,K,L,O,W statement or FIN R statement or UNTIL E ELSE only S SELECT ITEM or FIifficult to see how to use it by trying the examples provided. Examples: STAGE2 ALXTEST.ASM,ALXTEST.LST=ALX.MAC,ALXTEST.ALX STAGE2 BOUT.ASM,BOUT.LST=ALX.MAC,BOUT.ALX IMPLEMENTATION NOTES: > means push ^ means pop C means condition ( OTHERWISE ) L3 JMP L3 ^B FIN ----------------------------------------------------------- >n >S SELECT >n+1 >I ( V1 ) CPI V1 JNZ n+1 ^I ^n+1 FIN JMP n n+1: >n+3 >I ( V2 | V3 | V4 ) CPIprocess statement .DUMP STACK~ ~ --------------------------------------- >>`| FIN`~ `10|_FIN`20`F14~ ~ --------------------------------------- >>`| UNTIL`~ `10|_UNTIL`20`F14~ ~ --------------------------------------- >>`~ `10`F14~ ~ ------------N B BRANCH ITEM or FIN tatements are expected. I,K,L,O,W statement or FIN R statement or UNTIL E ELSE only S SELECT ITEM or FI Stack Source Statements Generated Code >n >K IF ( C ) JCF n ^K ^n FIN n: ----------------------------------------------------------- >n >n+1 >W WHEN ( C ) JCF n+1 ^W >E FIN JMP n ^E ^n+1 >K ELSE n+1: ~`~`0 (+-*/) MACROS FOR 8080 ASSEMBLY LANGUAGE EXTENSION PREPROCESSOR .HELLO~ -- ALX 2.6a 03/19/81 For CPMUG`F15~ ~ ------------------------------------ .LSKIP `~ ;To increment label counter by P1 `10`F7~ .INCSYM~ `F8~ ~ .INCSYM~ `01`16~ ~ - >n >n+1 >L WHILE ( C ) n+1: JCF n ^L ^n+1 ^n FIN JMP n+1 n: ----------------------------------------------------------- >n >R REPEAT n: ^R ^n UNTIL ( C ) JCF n ---------------------------------------------- V2 JZ n+2 CPI V3 JZ n+2 CPI V4 JNZ n+3 n+2: ^I ^n+3 FIN JMP n n+3: >O ( OTHERWISE ) ^O FIN ^S ^n FIN n: -----------------------------------------------------------abel `10:`F14~ ; output label to listing channel `10:`F13~ ; output label to ASM file .IF `20= SKIP 1~ `20~ ; pass on rest of statement for processing ~ --------------------------------------- PROCEDURE `~ ;To recognize PROCEDURE de .. JZ `30~ ; output jump if match instruction `F8~ ; end of loop ~ --------------------------------------- .ITEM B(`OTHERWISE`)`~ ;To recognize BRANCH catch all ITEM .. JMP `30~ ; output jump instruction ~ ---------------------------------ck .PUSH K~ ; push code "K" - IF or WHEN ELSE term. ~ --------------------------------------- .ELSE `~ .PUSH `10~ ; restore stack .SERR ELSE~ ~ --------------------------------------- .STM BRANCH`~ ;To recognize BRANCH statement ...BRAN------------------- .PROC `~ .PROC `10~ ~ --------------------------------------- .PROC `~ `10`27 ; ~ ; scan with break on " " or ";" or TAB .STO ^PROC=`20~ ~ --------------------------------------- ;`~ ;To accept comment line ;`10`F14~ (`)`~ ;To recognize SELECT or BRANCH ITEM ...(`10)`20~ ; output comment line to ASM file .TOS~ ^CSI`36 .ITEM `31(`10)`20~ ~ --------------------------------------- .ITEM B(`)`~ ;To recognize simple BRANCH ITEM .. CPI `10~ ; output compal n .PUSH `02~ ; push label n+1 .PUSH W~ ; push code "W" - WHEN .JCF `20,`02~ ; output conditional jump to n+1 .XSTM `30~ ; process remainder of line ~ --------------------------------------- .STM ELSE`~ ;To recognize ELSE stateclaration .IF ^CSP<1 SKIP 4~ ^DBG`86 `81`86 .STO ^DBG=T~ .DUMP STACK~ .STO ^DBG=`80~ .ERR STACK NOT EMPTY -- CHECK CONTROL STRUCTURES~ .LET ^CSP=0~ ; clear control stack .LET ^LEV=0~ ; control structure level .STO ^IND=~ ; clear inde .CHECK SELECT~ .PUSH `01~ ; push label n .PUSH S~ ; push code "S" - SELECT .INCLEV~ ~ --------------------------------------- .STM EXECUTE`(`)`~ ;To recognize EXECUTE statement .PUSH `01~ ; push label n .PUSH X~ ; push code "XCH`10~ ; output comment line to ASM file .CHECK BRANCH~ .PUSH B~ ; push code "B" - BRANCH .INCLEV~ ~ --------------------------------------- .STM SELECT`~ ;To recognize SELECT statement ...SELECT`10~ ; output comment line to ASM file; output to listing channel ~ --------------------------------------- `~ ;To accept any other line .IF `10-= SKIP 1~ ; if P1 is null `16~ ; P1 = " " `10`F14~ ; output to listing channel `10`F13~ ; output to ASM file ~ -------re instruction .. JZ `20~ ; output jump if match instruction ~ --------------------------------------- .ITEM B(`|`)`~ ;To recognize BRANCH ITEM with OR `10|`20`47|~ ; scan with break on OR symbol .. CPI `40~ ; output compare instruction ment ...ELSE`10~ ; output comment line to ASM file .POP~ ^CSI`96 .ELSE `91~ ; process else or flag error .XSTM `10~ ; process remainder of line ~ --------------------------------------- .ELSE E~ .POPL~ ; output label n+1 from stantation string ^PROC`86 .PROC `10~ `F14~ - - - - - - - - - - - - - - - - - - - - - - - - - - `81`F14~ `F14~ PROCEDURE `10`F14~ ; output to listing channel `F14~ `81: ; - - - - - - - - - - - - - - PROCEDURE `10`F13~ ~ --------------------" - EXECUTE .INCLEV~ .. LHLD `20~ .. PCHL ~ ~ --------------------------------------- .STM SETNEXT`(`=`)`~ ;To recognize SETNEXT statement ^TRIM`86 .TRIM `30~ .. LXI H,`81~ .TRIM `20~ .. SHLD `81~ ~ --------------------------------------- .STM onditional jump to n .XSTM `30~ ; process remainder of line ~ --------------------------------------- .STM WHEN`(`)`~ ;To recognize WHEN statement ...WHEN (`20)`30~ ; output comment line to ASM file .CHECK WHEN~ .PUSH `01~ ; push labe-------------------------------- .STM IF`(`)`~ ;To recognize IF statement ...IF (`20)`30~ ; output comment line to ASM file .CHECK IF~ .PUSH `01~ ; push label n .PUSH K~ ; push code "K" - IF or WHEN ELSE .JCF `20,`01~ ; output c------ .ITEM S(`)`~ ;To recognize simple SELECT ITEM .PUSH `01~ ; push label n+x .PUSH I~ ; push code "I" - SELECT ITEM .. CPI `10~ ; output compare instruction .. JNZ LLZ`01~ ; output JNZ n+x .XSTM `20~ ; process remainder ; success: point to exit label on stack .STO ^CSI=`81~ ; save exit label ~ --------------------------------------- .STM FIN`~ ;To recognize FIN terminator ...FIN`10~ ; output comment line to ASM file .DECLEV~ .POP~ ^CSI`96 .FIN `91~ ;.LOOP `,`~ ;To setup loop for WHILE, REPEAT or LOOP .PUSH `10~ ; put exit label on stack .PUSH `01~ ; put loop label on stack .PUSH `20~ ; put structure code on stack ..LLZ`01: ~ ; output loop label ~ ---------------------------for match .XSTM `30~ ; process remainder of line ~ --------------------------------------- .ITEM S(`OTHERWISE`)`~ ;To recognize SELECT catch all ITEM .PUSH O~ ; push code "O" - OTHERWISE .XSTM `30~ ; process remainder of line ~ -------------------------------------- .BRK~ ;To search control stack for exit label .IF ^CSP>0 SKIP 2~ ; when stack empty .SERR BREAK~ ; BREAK out of place `F9~ ; else .LET ^CSB=^CSP+1~ ; search pointer = stack pointer + 1 ^CSB`96~ ^CSP`Fss remainder of line ~ --------------------------------------- .STM LOOP`~ ;To recognize unconditional LOOP statement ...LOOP`10~ ; output comment line to ASM file .CHECK LOOP~ .LOOP `01,L~ ; setup loop .XSTM `10~ ; process remainder of line ~ --------------------------------------- .ITEM S(`|`)`~ ;To recognize SELECT ITEM with OR .PUSH `02~ ; push label n+x+1 .PUSH I~ ; push code "I" - SELECT ITEM `10|`20`47|~ ; scan with break on OR symbol .. CPI `40~ ; outpNTIL R,`~ .DECLEV~ .POP~ ^CSI`96 .JCF `10,`91~ ; output conditional jump to n .POPL~ ; output label from stack ~ --------------------------------------- .UNTIL `,`~ .PUSH `10~ ; restore stack .SERR UNTIL~ ~ ------------------------------------- .STM UNTIL`(`)`~ ;To recognize UNTIL termination of REPEAT ...UNTIL (`20)`30~ ; output comment line to ASM file .POP~ ^CSI`96 .UNTIL `91,`20~ ; generate conditional jump or flag error ~ --------------------------------------- .U--------------------------------- .ITEM X(`)`~ ;To recognize EXECUTE item (state) .PUSH Y~ ^LABEL`86 .LABEL `10~ ..`81: ~ .XSTM `20~ ; process remainder of line ~ --------------------------------------- .LABEL `~ .LABEL `10~ ~ -----------7~ ; for i = 1 to stack size .LET ^CSB=^CSB-1~ ; decrement search pointer ^CS`91`86 ^BRK`81`86~ .IF `81-= SKIP 3~ ; if loop code found goto success `F8~ ; fin .SERR BREAK~ ; BREAK out of place `F9~ ; exit `91-2`96 ^CS`94`86~ of line ~ --------------------------------------- .STM REPEAT`~ ;To recognize REPEAT statement ...REPEAT`10~ ; output comment line to ASM file .CHECK REPEAT~ .LOOP `01,R~ ; setup loop .INCLEV~ ~ --------------------------------------- ut compare instruction .IF `43-=| SKIP 2~ ; if break char. is OR .. JZ LLZ`01~ ; output jump to match .SKIP 1~ ; else end of line .. JNZ LLZ`02~ ; output jump to nomatch `F8~ ; end of scan loop ..LLZ`01: ~ ; output label n+x: -------------- .STM BREAK`IF`(`)`~ ;To recognize loop BREAKout statement ...BREAK IF (`30)~ ; output comment line to ASM file .CHECK BREAK IF~ .BRK~ ; search stack for exit label ^CSI`86 .JCT `30,`81~ ; GEN conditional branch ~ --------------------------------- .STM WHILE`(`)`~ ;To recognize WHILE statement ...WHILE (`20)`30~ ; output comment line to ASM file .CHECK WHILE~ .LOOP `01,L~ ; setup loop .JCF `20,`01~ ; output conditional jump to n .XSTM `30~ ; proce---------------------------- .LABEL `~ `10`27 : ~ .STO ^LABEL=`20~ ~ --------------------------------------- .ITEM `(`)`~ ;To recognize SELECT ITEM out of place .SERR SELECT, BRANCH ITEM~ .ITEM S(`20)`30~ ; process line anyway ~ ------------- process FIN by code found on stack ~ --------------------------------------- .FIN B~ ;To terminate BRANCH ~ --------------------------------------- .FIN I~ ;To terminate SELECT ITEM .POP~ ^CSI`96 `91`96~ ; pop label n+x .POP~ ^CSI`86^CSP=^CSP-1~ `F9~ .STO ^CSI=*~ `FE~ ~ --------------------------------------- .TOS~ ^CSP`96 .IF `91<1 SKIP 2~ ^CS`91`86 .STO ^CSI=`81~ `F9~ .STO ^CSI=*~ ~ --------------------------------------- .JCT `,`~ ;To output jump condition true .STO ^YSTM ~ ~ --------------------------------------- .YSTM ;`~ ~ --------------------------------------- .YSTM `~ .CHECK `10~ `10`F13~ ; output to ASM file .STM FIN~ ; generate a FIN statement ~ --------------------------------------- .TRIM O~ ;To terminate SELECT OTHERWISE ITEM ~ --------------------------------------- .FIN S~ ;To terminate SELECT .POPL~ ; output label n: from stack ~ --------------------------------------- .FIN W~ ;To terminate WHEN branch .POP~ ^CSI`ck .LET ^CSP=^CSP+1~ ^CSP`96 .STO ^CS`91=`10~ ~ --------------------------------------- .POPL~ ;To output label from stack .POP~ ^CSI`96 ..LLZ`91: ~ ~ --------------------------------------- .POPJ~ ;To output jump to label from stack .POP~ R STACK NOT EMPTY -- CHECK CONTROL STRUCTURES~ .STO ^DBG=T~ ; set debug mode .DUMP STACK~ ; send stack contents to LST file LLZ`01 Next label not used`F15~ `F0~ ; stop processing ~ --------------------------------------- .STM `~ ;To reco `81`86~ ; pop code "S" .TOSJ~ ; output jump to label n (stack top) .PUSH `80~ ; push code "S" back on stack ..LLZ`90: ~ ; output label n+x: ~ --------------------------------------- .FIN K~ ;To terminate IF or WHEN ELSE .POP------------------------------------ .INCLEV~ .LET ^LEV=^LEV+1~ .CAT ^IND, | ~ ; append to indentation string ~ --------------------------------------- .DECLEV~ ;To decrement control structure level ^LEV`16 .IF `11<1 SKIP 2~ .LET ^LEV=^LEV-1~ `~ ;To strip leading space .TRIM `10~ ~ --------------------------------------- .TRIM `~ ;To strip leading tab .TRIM `10~ ~ --------------------------------------- .TRIM `~ ;To save line without leading spaces and tabs .STO ^TRIM=`10~ ~ ---96 `91`96~ ; pop label n+1 .TOSJ~ ; output jump to label n (stack top) .PUSH `90~ ; put label n+1 back on the stack .PUSH E~ ; push code "E" - ELSE ~ --------------------------------------- .FIN X~ ;To terminate EXECUTE .POPL~ ^CSI`96 .. JMP LLZ`91~ ~ --------------------------------------- .TOSJ~ ;To output jump to label on stack top .TOS~ ^CSI`96 .. JMP LLZ`91~ ~ --------------------------------------- .POP~ ^CSP`96 .IF `91<1 SKIP 3~ ^CS`91`86 .STO ^CSI=`81~ .LET gnize non control statements .CHECK `10~ `10`F13~ ; output to ASM file ~ --------------------------------------- .XSTM `~ .INCLEV~ .TRIM `10~ ; strip leading spaces and tabs ^TRIM`26 .YSTM `21~ ~ --------------------------------------- .L~ ; output label n: from stack ~ --------------------------------------- .FIN L~ ;To terminate WHILE loop .POPJ~ ; output jump to n+1: from stack .POPL~ ; output label n: from stack ~ --------------------------------------- .FIN ^IND`26 .UND `21~ ; remove " | " from indentation string ~ --------------------------------------- .UND ` | ~ ;To remove one level of indentation .STO ^IND=`10~ ~ --------------------------------------- .PUSH `~ ;To push something on the sta----------- .FIN `~ ;To recognize a wayward FIN .INCLEV~ .PUSH `10~ ; restore stack .SERR FIN~ ~ --------------------------------------- END-`~ ;To recognize END-OF-FILE END-`10`F14~ ^CSP`26 .IF `21<1 SKIP 3~ ; if stack not empty .ER ~ --------------------------------------- .FIN Y~ ;To terminate EXECUTE ITEM .POP~ ^CSI`86 `81`86~ ; pop code "X" .TOSJ~ ; output jump to label n (stack top) .PUSH `80~ ; push code "X" back on stack ~ ----------------------------TMP=~ ; set string to null `10`37 ~ ; scan and break on space or tab .CAT ^TMP,`30~ ; save non space or tab characters `F8~ ; end of loop ^TMP`16 `11`16~ ; retrieve compressed condition string .. `11 LLZ`20~ ; get jump inst. moves rate register to int mask reg MCONT EQU PMMI+3 ; modem control register PROCEDURE CONST CALL DJTSTAT MVI A,0FFH RZ ; return if terminal input data ready CALL MISTAT ; check modem input status RET PROCEDURE CONOUT PUSH B CALL FLUS .STO ^^R=SOK~ .STO ^^W=SOK~ .STO ^^Y=SOK~ .STO ^^*=SOK~ .STO ^BRKL=LOOP~ BREAK OK FOR LOOP, OR WHILE .STO ^BRKR=LOOP~ BREAK OK FOR REPEAT .STO CARRY=JC~ .STO NOCARRY=JNC~ .STO PLUS=JP~ .STO MINUS=JM~ .STO ZERO=JZ~ .STO NOTZERO=JNZ~ .STO EVEN=6 `11`F7~ ^CNT`26 ^CS`21`36~ ^CS`21 "`31"`F14~ .LET ^CNT=^CNT-1~ `F8~ ^LEV`46~ ^LEV =`41`F14~ ~ --------------------------------------- .DEBUG~ .STO ^DBG=T~ ~ --------------------------------------- .UNBUG~ .STO ^DBG=F~ ~ --------------------- ; Local data storage (initialized) ; CONNECT: DB 0 ; false - modem not connected ; ; Terminal access ; DJROM EQU 0F800H DJCIN EQU DJROM+3 DJCOUT EQU DJROM+6 DJTSTAT EQU DJROM+21H ; ; Modem access ; PMMI EQU 0C0H ; base port address USTAT EQ ~ .IF `=` SKIP `~ `F50~ ~ .IF `-=` SKIP `~ `F51~ ~ .IF `<` SKIP `~ `F6-~ ~ .IF `==` SKIP `~ `F60~ ~ .IF `<>` SKIP `~ `F61~ ~ .IF `>` SKIP `~ `F6+~ ~~ ------------ END OF MACROS ------------------- END OF MACROS ------------ .LET ^ERR=0~from table and output ~ --------------------------------------- .JCF `,`~ ;To output jump on condition false .STO ^TMP=~ ; set string to null `10`37 ~ ; scan and break on space or tab .CAT ^TMP,`30~ ; save non space or tab characters `JPE~ .STO ODD=JPO~ .STO -CARRY=JNC~ CONDITIONAL JUMP LOOK UP TABLE .STO -NOCARRY=JC~ .STO -PLUS=JM~ .STO -MINUS=JP~ .STO -ZERO=JNZ~ .STO -NOTZERO=JZ~ .STO -EVEN=JPO~ .STO -ODD=JPE~ ------------------ ...`~ ;To output comment line to ASM file ;; `10`F13~ ~ --------------------------------------- ..` ` `~ ;To output line to ASM file `10 `20 `30`F13~ ~ --------------------------------------- .SERR `~ .ERR "`10" NOT ALLOWEU PMMI ; uart status input UCONT EQU PMMI ; uart and modem control output UDATA EQU PMMI+1 ; uart incoming and outgoing data MSTAT EQU PMMI+2 ; modem status input MRATE EQU PMMI+2 ; timer rate regester and temp reg for int mask MINT EQU PMMI+3 ; input .LET ^LEV=0~ CONTROL STRUCTURE LEVEL .STO ^IND=~ EMPTY INDENTATION STRING .LET ^CSP=0~ EMPTY STACK .STO ^CS0=*~ EMPTY STACK ENTRY .STO ^DBG=F~ DEBUG OFF .STO ^^I=SOK~ STATEMENT OK IF "I" IS ON STACK .STO ^^K=SOK~ .STO ^^L=SOK~ .STO ^^O=SOK~F8~ ; end of loop ^TMP`16 -`11`16~ ; retrieve compressed condition string .. `11 LLZ`20~ ; get jump inst. from table and output ~ --------------------------------------- .DUMP STACK~ ^DBG`56 .IF `51=T SKIP 1~ `F9~ .LET ^CNT=^CSP~ ^CSP`1; CP/M console I/O module supporting terminal and modem in "parallel" ; ; Terminal is attached to Disk Jockey serial port ; Modem is PMMI S100 board ; BEGIN ; ; Entry points ; ENTRY CONST,CONIN,CONOUT ; ; External references ; EXTRN FLUSH ;------- .CHECK `~ ;To check top of stack for stmt allowed .TOS~ ^CSI`26 ^^`21`26~ .IF `21=SOK SKIP 1~ .SERR `10~ ~ --------------------------------------- .CAT `,`~ `11`20`26 `F3~ ~ .STO `=`~ `F3~ ~ .LET `=`~ `24`26 `F3~ ~ .SKIP `~ `F4~ D HERE~ ~ --------------------------------------- .ERR `~ ;To output error messages >>> ERROR <<< `10`26~ `20`F13~ ; to ASM file `20`F14~ ; to listing file `20`F15~ ; to console .LET ^ERR=^ERR+1~ ~ --------------------------------H POP B CALL DJCOUT ; output character to terminal CALL MOUT ; output character to modem if connected RET PROCEDURE CONIN CALL FLUSH LOOP CALL DJTSTAT IF ( ZERO ) ; data waiting CALL DJCIN ; get data from terminal ANI 7FH RET FECEIVE STATUS 1=READY 0=NOT READY ; MISTAT: IN SIO ANI 1 ; RECEIVER READY STATUS BIT RET ; ; ; CHECK SEND READY STATUS ; MOSTAT: IN SIO ANI 2 RET ; ; ; CHECK CONSOLE READY STATUS 1=READY 0=NOT READY ; CISTAT: IN KBD ANI 2 RZ 2 ; data available (low true) SUI 1 ; if ( DAV = 0 ) A=FF SBB A ; else A=0 FIN FIN ORA A ; set zero flag RET PROCEDURE CONSEQ MVI A,7FH ; DTR,300,ESS OUT MCONT CALL DELAY MVI A,5EH ; 2s, NP, 8 bits, Answer OUT UCONT MVI D,0 DAD D INX H MVI M,0 ; MAKE SURE DELIMITER AT END OF NAME LXI H,FTAB LXI D,CBUFF+2 CALL DOPEN RET ; ; ; CRLF: MVI E,0DH CALL CO MVI E,0AH CALL CO RET ; ; ; BLK: MVI E,' ' JMP CO ; ; BDOS EQU 0005H ; BDOS ENTRY RET PROCEDURE MOUT LDA CONNECT ORA A IF ( NOT ZERO ) ; connected REPEAT IN MSTAT ANI 4 BREAK IF ( NOT ZERO ) ; carrier lost IN USTAT ANI 1 UNTIL ( NOT ZERO ) ; transmit buffer empty (TBMT) CPI 1 ; TBMT IF ( ZERO ) MOV A,C IN CALL MISTAT IF ( NOT ZERO ) ; data waiting CALL MINP ; get data from modem ANI 7FH RET FIN FIN PROCEDURE MISTAT LDA CONNECT ORA A WHEN ( ZERO ) ; modem disconnected IN MSTAT ANI 2 IF ( ZERO ) ; ringing CALL CONSEQ ; st PUSH B MVI B,150 ; 15 seconds REPEAT CALL DELAY IN MSTAT ANI 4 BREAK IF ( ZERO ) ; carrier detected DCR B UNTIL ( ZERO ) POP B CALL DELAY IN UDATA IN UDATA ; clear uart receiver MVI A,52 ; 300 baud OUT MRATE MVI A,5CHPOINT KBD EQU 02H ; KEYBOARD PORT SIO EQU 50H ; 2SIO BOARD ORIGIN ; ; ; OUTPUT TO CONSOLE ; CO: MVI C,2 CALL BDOS RET ; ; ; OUTPUT (E) TO MODEM ; MO: IN SIO ANI 2 ; TRANSMIT READY BIT JZ MO MOV A,E OUT SIO+1 RET ; ; ; CHECK R OUT UDATA ; send data through modem FIN FIN MOV A,C RET PROCEDURE MINP IN UDATA RET END END-OF-FILE  carrier lost IN USTAT ANI 1 UNTIL ( NOT ZERO ) ; transmit buffer empty (TBMT) CPI 1 ; TBMT IF ( ZERO ) MOV A,C art connect sequence STA CONNECT FIN MVI A,0 ; no data waiting FIN ELSE IN MSTAT ANI 4 WHEN ( NOT ZERO ) ; carrier lost CALL DCONSEQ ; start disconnect sequence STA CONNECT MVI A,0 ; no data waiting FIN ELSE IN USTAT CMA ANISREV EQU 20H ; 06/14/79 R. CURTISS DERIVED FROM NORDATA1 ; ; ; OPEN FILE FOR READ OR WRITE ; OPENF: PUSH B ; SAVE ACCESS CODE MVI C,10 LXI D,CBUFF CALL BDOS ; GET FILE NAME FROM CONSOLE POP B LXI H,CBUFF+1 ; CHAR COUNT POINTER MOV E,M 1 sec OUT MRATE REPEAT IN MSTAT ANI 80H UNTIL ( ZERO ) ; timer bit low REPEAT IN MSTAT ANI 80H UNTIL ( NOT ZERO ) ; timer bit high RET PROCEDURE DCONSEQ MVI A,3FH ; 300, ESS OUT MCONT ; force hangup XRA A ; connect false flag ; 2s, NP, 8 bits, Normal (auto hangup if carrier lost) OUT UCONT IN MSTAT ANI 4 MVI A,0 RNZ ; return if no carrier ;+++++++++++++ send signon message and password request MVI A,0FFH ; connect flag RET PROCEDURE DELAY MVI A,250 ; . ORI 0FFH RET ; ; ; GET DATA FROM MODEM ; MI: IN SIO ; GET STATUS ANI 1 JZ MI IN SIO+1 RET ; ; ; GET DATA FROM CONSOLE ; CIE: CALL CI MOV E,A PUSH PSW CALL CO ; ECHO INPUT POP PSW RET CI: CALL CISTAT ; GET KEYBOARD STATUS------------------------------- .ADD $=$# :CAT $10 $20# # ------------------------------------------- :CAT $ $# :STO $10=$11;$20# # ------------------------------------------- :STO $=$# $F3# # ---------------------------------------- :IF $=$ SKIP line !11!26% 8. Extract info !F14% 9. Output 1111111= 22222222222222222% 10. Format % 11. End of macro END# 12. Template line !F0% 13. Terminate processing %% 14. End of macros MEM[25]=TWENTY FIVE# MEM[ABC]=HELLO# MEM[EQUATION] ; 100 8 BITS, 2 STOP, NO PARITY ; 00 /RTS LOW, XMIT INT. DISABLE ; 11 /RTS HIGH, BREAK LEVEL TRANSMIT ; 0 RCV. INTERRUPT DISABLE ; ; ; TRANSMIT BREAK LEVEL ; BRK: MVI A,71H OUT SIO RET ; ; ; INITIALIZE SIO FOR NORMAL OPER# $F3# # ----------------------------------------- .DUMP# .DUMP KLIST# # ------------------------------------------ .DUMP $# $11$47;# :IF $40= SKIP 4# $F15# ............ $40$F15# $F15# .RECALL $40# $F8# # -----------------------------------B DCR B JNZ MSG4 MSG5: XRA A STA TAB ; RESET TAB COLUMN COUNT RET ; ; URN JMP MSG5 MSG2: CALL CO ; OUTPUT CHARACTER RET MSG3: INR B ; TAB COUNT MSG4: PUSH B MVI E,' ' CALL CO POP JZ CI ; JUMP IF NO DATA READY IN KBD+1 ; GET KBD DATA ANI 7FH PUSH PSW LDA ULTOG ; UPPER/LOWER CASE TOGGLE ORA A JNZ CIX ; JUMP IF CASE SWITCH REQUIRED POP PSW RET CIX: POP PSW CPI 'A' RC ; RETURN IF < 'A' CPI 'Z'+1 JC KI=A=2*(B+C)# MEM[X=Y]=Z# MM[12]="E" MISSING# MEM [XYZ]=SPACE AFTER "MEM"# MEM[ABC)]=UNBALANCED STRING# MEM[ABC]=UNBALANCED (STRING# PRINT MEM[25]# PRINT MEM[ABC]# PRINT MEM[PDQ]# FORMAT MEM[25]# FORMAT MEM[ABC]# FORMAT MEM[PDQ]# END# ATION ; SMODE: MVI A,03H OUT SIO ; RESET MVI A,11H ; NORMAL OPERATION OUT SIO RET ; ; ; DELAY 100*(A) MILLESECONDS ; DELAY: LXI B,29B4H ; Z80 VALUE D1: DCX B INR B DCR B JNZ D1 DCR A JNZ DELAY RET ; ; ; TYPE MESSAGE W------- .STOP# $F0# # ------------------------------------------ .WRITE# KLIST$16 $11$47;# :IF $40= SKIP 1# .SAVE $40=$41$F13# $F8# # ------------------------------------------ .RECALL $# $11$27;# $20$F15# $F8# # ------------#$%!0 (+-*/) 0. Special character selection MEM[$]=$# 1. Template line !F3% 2. Store into memory % 3. End of macro PRINT MEM[$]# 4. Template line !10=!11!F14% 5. Extract info and output % 6. End of macro FORMAT MEM[$]# 7. TemplateNV ; JUMP IF IN RANGE 'A'-'Z' CPI 'A'+20H RC ; RETURN IF < LOWER CASE 'A' CPI 'Z'+21H RNC ; RETURN IF > LOWER CASE 'Z' KINV: XRI 20H ; FLIP CASE BIT RET ; ; ; CONTROL BYTE FOR SIO ; X XX XXX XX ; 01 /16 ; 11 MASTER RESET#$#$0 (+-*/) SPECIAL SYMBOL SELECTION FOR FOLLOWING MACROS .SAVE $=$# $F3# :CAT KLIST $10# ADD ITEM TO DIRECTORY LIST # ------------------------------------------ .CLEAR $# :STO $10=# # ------------------------------------------ .RESAVE $=$A,E CPI 'I'-40H JZ MSG3 ; JUMP IF TAB CPI 0DH JNZ MSG2 ; JUMP IF NOT CARRIAGE RETURN CALL CO ; OUTPUT CARRIAGE RETURN JMP MSG5 MSG2: CALL CO ; OUTPUT CHARACTER RET MSG3: INR B ; TAB COUNT MSG4: PUSH B MVI E,' ' CALL CO POP ITH TABS EXPANDED ; MSG: MOV A,M ; GET NEXT CHARACTER OF MESSAGE ORA A RZ ; RETURN IF END OF MESSAGE (NULL) PUSH H MOV E,A CALL MSG1 POP H INX H JMP MSG MSG1: LDA TAB ; TAB COLUMN COUNTER DCR A ANI 7 STA TAB MOV B,A MOV $# $F50# # ----------------------------------------- .$# WHAT IS THE MEANING OF THIS ??? $10$F15# # ------------------------------------------- $# .$10# ][ ................................................][$F15# # -------------------------------- JMP MEMSET ; ENTRY POINT - SET UP FLUB MEMORY BOUNDS NOP PROGRM: JMP PROGR ; EXTERNAL REFERENCE - STAGE2, FLT1, FLT2 NOP EXIT: JMP 0000H ; EXTERNAL REFERENCE - RETURN TO CP/M NOP ; ; ------------------------------------- ; ; MAIN PROGRAM 22222222222 # ---------------- ..$# $10$F15# # $# ..>>> NO EXAMPLE PREPARED# # .CONSOLE# 5$F2# ## HELP# ..READY FOR INPUT FROM CONSOLE# .CONSOLE# QU 12H ; 05/29/79 R. CURTISS IWRT5,MCHOFF ;REV EQU 11H ; 05/29/79 R. CURTISS MORE,FPRS,FNAME ;REV EQU 10H ; 05/29/79 R. CURTISS NEW VERSION ; ; STAGE2 MAIN PROGRAM AND I/O OPERATION PACKAGE ; ; REVISION B02 03/15/78 R. CURTISS ADD COMMENTSRAMETER# .L C2 $$/GET FROM MEMORY USING PARAMETER - GEN IF UNDEFINED# .L C4 $$/EVALUATE EXPRESSION# .L C5 $$/GET LENGTH OF EXPRESSION# .L C6 $$/REPLACE PARAMETER# .L C7 $$/CONTEXT CONTROLLED ITERATION - BREAK ON , ;# .L C8 $$/GET INTERNAL CODE FOR CH--------- .DIR$# .RECALL KLIST# # ---------------------------------------- .HELP# .RECALL HELP# # --------------------------------------- .CONSOLE# 5$F2# # DISK# 1$F2# ## ----------- END OF MACROS ------------------------- :STO HELP=ADD =<#$#$0 (+-*/) C0 $# .."$10"# # C1 $# .."$11"# # C2 $# .."$12"# # C4 $# .."$14"# # C5 $# .."$15"# # C6 $# YOUR STRING REPLACED BY THIS$16# .."$10"# # ; MAIN EQU 100H PROGR EQU 1000H ORG MAIN JMP F4IO ; MAIN ENTRY POINT - PROGRAM STARTUP DB REV ; IOOP REVISION JMP IOOP ; ENTRY POINT - I/O PACKAGE DB DREV ; DISK I/O REVISION JMP TRAP ; ENTRY POINT - END OF MACROS DETECTED NOP ARACTER# .L F0/TERMINATE PROCESSING# .L F1/OUTPUT REQUEST# .L F3 $$=$$/STORE INTO MEMORY# .L F7 $$/COUNT CONTROLLED ITERATION# .L FE/FORCE ERROR TRACE BACK# # ---------------- .L $/$# $F15# 1111111122222222222222222222222222222222222222222INFO>;DIR;HELP;RECALL ;SAVE =;WRITE;RESAVE =;CLEAR ;STOP;DUMP .ADD HELP= IS STRINGS SEPERATED BY SEMICOLONS :STO KLIST= HELP .CONSOLE REV EQU 16H ; 06/13/79 R. CURTISS NO ERR ON REWIND CLOSED FILE ;REV EQU 15H ; 06/10/79 R. CURTISS DREV, C, ICNTL ;REV EQU 14H ; 05/31/79 R. CURTISS FIX LF, MORE, XDEVC, GBPDEV ;REV EQU 13H ; 05/30/79 R. CURTISS XDEVC FIX, PATCH SPACE ;REV E$F7# ..REPEAT $10 TIMES# $F8# # FE# $FE# # ----------------- HELP# ..S - SYMBOL GEN C - CONVERSION F - PROCESSOR FUNCTION# .L S/REQUEST NEXT SYMBOL FROM GENERATOR# .L C0 $$/PARAMETER AS IS# .L C1 $$/GET FROM MEMORY USING PA C7 $# $10$27,;# .."$20" "$23"# $F8# # C8 $# .."$18"# # S# .."$01"# # F0# $F0# # F1# ..OUTPUT REQUEST# # F3 $=$# $F3# # F7 $# $10; DS 38H ; STACK SPACE F4IO: LXI SP,F4IO ; CALL INIT CALL PROGRM ; ; CLOSE ALL CHANNELS ; CALL GCLOSE CALL EXIT JMP F4IO ; ; -------------------------------------- ; ; INITIALIZE CHANNEL I/O TABLE ; INIT: MVI B,6*MAXCH LXI D RET ; LL7: MVI A,2 ; ILLEGAL OPERATION STATUS RET ; ; --------------------------------- ; ; READ OPERATION ; LL10: MOV A,B ; GET CHANNEL STATUS DCR A JZ LL11 ; JUMP IF CLOSED DCR A JZ LL12 ; JUMP IF OPEN FOR READ DCR A JZ LL7 ; WRITE OPERATION ; REGISTER BEFORE AFTER ; A 1 STATUS ; B CHANNEL ; HL START OF LINE ; BUFFER LENGTH ; LINE DATA ; ; CLOSE/REWIND OPERATION ; REGISTER BEFORE AFTER ; A 0 STATUS ; B CHANNEL ; IOOP: STA JOP KCH+1 READ ACCESS ; 0 - ILLEGAL ; 1 - CHANNEL AVAILABLE FOR READ ; ; W KCH+2 WRITE ACCESS ; 0 - ILLEGAL ; 1 - MACHINE READABLE OUTPUT ; 2 - HUMAN READABLE OUTPUT ; 3 - FIRST LINE OF HUMAN READABLE OUTPUT ; ALLOWS TOP OF FORM ; ; D D MOV A,M ; CONTROL ACCESS = JCHAN(KCH+4) ; ORA A JZ LL3 ; JUMP IF CONTROL OPERATION UNAVAILABLE ; PUSH D ; SAVE KCH CALL ICNTL ; PERFORM CONTROL OPERATION POP D ; RESTORE KCH RET ; LL3: LXI H,JCHAN+6 ; SET CHANNEL STATUS TO INACTIVE------- ; ; I/O SUPERVISOR ; ; OPERATION CODE ; 0 - CLOSE ; 1 - WRITE ; -1 - READ ; ; OPERATION STATUS ; 0 - NORMAL ; 1 - EOF OR END OF MEDIUM ; 2 - ILLEGAL OPERATION ; 3+ ERROR CODE ; ; STATUS = IOOP ( OPERATION , CHANNEL , BUFFER ,CHAN LXI H,JCHAN+1 ; INIT1: LDAX D MOV M,A INX D INX H DCR B JNZ INIT1 ; CALL FINIT ; GET FILES FROM COMMAND LINE RET ; ; ----------------------------------------- ; ; INITIAL VALUES FOR CHANNEL CONTROL TABLE ; CHAN: ; R W O CIF CHANNEL > MAX CHANNEL ; CALL MCHOFF ; MAKE CHANNEL OFFSET XCHG SHLD CHOFF ; CHANNEL OFFSET XCHG ; LXI H,JCHAN+6 ; STATUS = JCHAN(KCH+6) DAD D MOV A,M ORA A JZ LL7 ; JUMP IF STATUS = UNAVAILABLE ; MOV B,A ; SAVE CHANNEL STATUS L; SAVE OPERATION CODE SHLD POINT ; SAVE BUFFER POINTER MOV A,B STA NCHAN ; SAVE CHANNEL NUMBER ORA A ; TEST CHANNEL NUMBER JM LL7 ; JUMP IF < 0 ERROR CONDITION JZ LL5 ; JUMP IF = 0 NULL CHANNEL BIT BUCKET ; CPI MAXCH+1 JP LL7 ; JUMP O KCH+3 OPEN ACCESS ; 0 - NO ACTION REQUIRED ; 1 - OPEN REQUIRED ; ; C KCH+4 CONTROL ACCESS (CLOSE) ; 0 - NO ACTION REQUIRED ; 1 - CLOSE REQUIRED ; ; U KCH+5 DEVICE CODE ; 0 - NULL DEVICE ; 1 - DISK ; 2 - CONSOLE ; 3 - LIST DEVICE DAD D MVI M,1 ; JCHAN(KCH+6) = 1 ; LL4: ; NORMAL TERMINATION XRA A ; SET OPERATION STATUS TO ZERO RET ; LL5: ; NULL CHANNEL I/O LDA JOP ORA A JP LL4 ; JUMP IF NOT READ OPERATION ; LL6: MVI A,1 ; EOF STATUS OR END OF MEDIUM ) ; (A) (B) (HL) ; ; MAXLEN: DB N ; LENGTH: DS 1 ; BUFFER: DS N+1 ; ; READ OPERATION ; REGISTER BEFORE AFTER ; A -1 STATUS ; B CHANNEL ; HL START OF LINE ; BUFFER MAXLEN LENGTH ; LINE DATA ; ; U S DB 1,0,1,1,2,1 ; CHANNEL 1 - INPUT FILE DB 1,1,1,1,1,1 ; CHANNEL 2 - SCRATCH FILE DB 0,1,1,1,2,1 ; CHANNEL 3 - OUTPUT FILE DB 0,1,1,1,3,1 ; CHANNEL 4 - LISTING FILE DB 1,1,0,0,2,4 ; CHANNEL 5 - CONSOLE I/O ; MAXCH EQU ($-CHAN)/6 ; ; ; RDA JOP ORA A JM LL10 ; JUMP IF READ OPERATION JNZ LL20 ; JUMP IF WRITE OPERATION ; ; ------------------------------------- ; ; CONTROL OPERATION ; MOV A,B ; GET CHANNEL STATUS CPI 1 JZ LL4 ; JUMP IF STATUS = CLOSED ; LXI H,JCHAN+4 DAEADING NOP RET ; ; -------------------------------------- ; ; SET FLUB MEMORY BOUNDS ; DE LOW LIMIT ; HL HIGH LIMIT ; MEMSET: LHLD 0006H ; GET BDOS ENTRY ADDRESS DCR H ; ONE PAGE LESS TO BE SAFE RET ; ; --------------------------------- ; ; S KCH+6 CHANNEL STATUS ; 0 - NOT AVAILABLE ; 1 - CLOSED ; 2 - OPEN FOR READ ; 3 - OPEN FOR WRITE ; 5 - END OF FILE ON READ ; END OF MEDIUM ON WRITE ; ; ------------------------------------- ; TRAP: NOP ; TRAP AT END OF MACRO R JUMP IF OPEN FOR WRITE ERROR DCR A JZ LL12 ; JUMP IF OPEN FOR BOTH READ AND WRITE DCR A JZ LL6 ; JUMP IF END OF FILE JMP LL7 ; ERROR ; LL11: LXI H,JCHAN+1 DAD D MOV A,M ; GET READ ACCESS PERMISSION ; ORA A JZ LL7 ; JUMP IF READINGR IWRTA: IWRTB: CALL GBPDEV ; HL - BUFFER POINTER ORA A ; A - DEVICE CODE RZ ; RETURN IF 0 - NULL DEVICE DCR A JZ IWRT1 ; JUMP IF 1 - DISK DEVICE DCR A JZ IWRT2 ; JUMP IF 2 - CONSOLE OUT DCR A JZ IWRT3 ; JUMP IF 3 - LIST DEVICE NTER DW 0 ; ACTUAL LINE LENGTH POINTER ; ; GET LINE FROM CONSOLE ; IRED2: XCHG DCX D DCX D CALL CIB ; INPUT BUFFER FROM CONSOLE MVI E,0AH CALL CO ; SEND LINE FEED TO CONSOLE LHLD POINT MOV A,M CPI 1AH ; CONTROL Z JZ IREOF ; JUMP IF JZ LL21 ; JUMP IF CLOSED DCR A JZ LL7 ; JUMP IF OPEN FOR READ DCR A JZ LL22 ; JUMP IF OPEN FOR WRITE DCR A JZ LL22 ; JUMP IF OPEN FOR READ OR WRITE DCR A JZ LL6 ; JUMP IF AT END OF MEDIUM JMP LL7 ; ERROR ; LL21: LXI H,JCHAN+2 DAD DET ; ; ------------------------------------- ; ; BUFFER WRITE ROUTINE ; IWRIT: LXI H,JCHAN+2 ; GET WRITE ACCESS DAD D MOV B,M ; JHOW = JCHAN(KCH+2) ; DCR B JZ IWRTB ; JUMP IF JHOW = 1 MACHINE READABLE FILE ; DCR B JZ IWRTA ; JUMP IF K DCR A JZ IRED2 ; JUMP IF 2 - CONSOLE IN IRED0: MVI A,1 ; END OF FILE OR ERROR CONDITION RET ; ; IRED1: PUSH H DCX H SHLD ARGLST+2 ; SET LENGTH POINTER DCX H SHLD ARGLST ; SET MAX LENGTH POINTER CALL GFTAB ; HL = FILE TABLE POIN NOT ALLOWED ; LXI H,JCHAN+6 DAD D MVI M,2 ; SET CHANNEL STATUS OPEN FOR READ ; LXI H,JCHAN+3 DAD D MOV A,M ; GET OPEN ACCESS FOR CHANNEL ORA A JZ LL12 ; JUMP IF OPEN NOT REQUIRED ; PUSH D ; SAVE KCH LXI B,IACCE ; READ ACCESS CALL P MVI C,',' CALL SCAN JZ MORE2 ; JUMP IF ',' FOUND MVI A,1 ; END OF FILE RET MORE2: INX H SHLD FNPTR1 ; IP = P+1 CALL GDEVIC ; GET DEVICE CODE DCR A JNZ MORE3 ; JUMP UNLESS 1 - DISK CALL GFTAB ; HL = FILE TABLE POINTER CALL DFIRST CHAR IN BUFFER IS ^Z XRA A ; NO ERROR RET ; ; ------------------------------------ ; ; CHECK FOR CHANNEL 1 MULTIPLE INPUTS ; MORE: LDA NCHAN DCR A JZ MORE1 ; JUMP IF CHAN 1 MVI A,1 ; END OF FILE RET MORE1: LHLD FNPTR1 ; P = I MOV A,M ; GET WRITE ACCESS ORA A JZ LL7 ; JUMP IF WRITING NOT POSSIBLE ; LXI H,JCHAN+6 DAD D MVI M,3 ; SET CHANNEL OPEN FOR WRITE ; LXI H,JCHAN+3 DAD D MOV A,M ; GET OPEN ACCESS ORA A JZ LL22 ; JUMP IF NO OPEN REQUIRED ; PUSH D JHOW = 2 HUMAN READABLE OUTPUT ; ; *** MAYBE OUTPUT FORM FEED MVI M,2 ; SET JHOW TO 2 TOP OF FORM DONE CALL GBPDEV ; HL - BUFFER POINTER CPI 3 ; A - DEVICE CODE JNZ IWRT1 ; JUMP UNLESS LIST DEVICE MVI E,0CH CALL LO ; FORM FEED TO PRINTETER POP D ; DE = BUFFER POINTER LXI B,ARGLST CALL LREAD ; READ LINE ORA A RZ ; RETURN IF NO ERROR OR EOF IREOF: CALL MORE ; CHECK FOR CHAN 1 MULTIPLE INPUTS JZ IREAD ; JUMP IF ANOTHER INPUT FILE RET ARGLST: DW 0 ; MAX LINE LENGTH POIIOPEN POP D ORA A RNZ ; RETURN IF OPEN ERROR ; LL12: PUSH D ; SAVE KCH CALL IREAD ; PERFORM READ OPERATION POP D JMP LL30 ; ; ------------------------------------- ; ; WRITE OPERATION ; LL20: MOV A,B ; GET CHANNEL STATUS DCR A CLOSE ; CLOSE DISK FILE MORE3: LHLD FNPTR MVI B,1 CALL XDEVC ; LU(1) = XUNIT(IP) ORA A JZ MORE8 ; ERROR IF NUL: CPI 3 JZ MORE ; ERROR IF LIST DEVICE LXI B,IACCE CALL IOPEN ; OPEN FILE IF DISK RET MORE8: MVI A,1 ; END OF FILE RD MVI M,5 ; SET STATUS TO EOF OR EOM RET ; ; -------------------------------------- ; ; BUFFER READ ROUTINE ; IREAD: CALL GBPDEV ; HL = BUFFER POINTER ORA A ; A = DEVICE CODE JZ IRED0 ; JUMP IF 0 - NULL DCR A JZ IRED1 ; JUMP IF 1 - DIS; SAVE KCH LXI B,OACCE ; WRITE ACCESS CALL IOPEN POP D ORA A RNZ ; RETURN IF OPEN ERROR ; LL22: PUSH D ; SAVE KCH CALL IWRIT ; PERFORM WRITE OPERATION POP D ; ; LL30: CPI 1 RNZ ; RETURN IF NOT EOF OR EOM ; LXI H,JCHAN+6 DAD MVI A,1 ; ERROR CONDITION RET ; ; IWRT1: LHLD POINT ; RECALL BUFFER POINTER LDA NCHAN ; RECALL CHANNEL NUMBER CPI 5 JZ IWRT2 ; JUMP IF CONSOLE CHANNEL PUSH H CALL GFTAB ; HL = FILE TABLE POINTER POP D ; DE = BUFFER POINTER MOV B,D PTR3 MVI B,3 CALL XDEVC ; LU(3) = XUNIT(OP) LHLD FNPTR4 MVI B,4 CALL XDEVC ; LU(4) = XUNIT(LP) XRA A ; NO COMMAND ERROR DETECTED RET FPRS8: ORI 1 ; COMMAND ERROR DETECTED RET ; ; ------------------------------------- ; SCAN: MOV M,A INX H INX D DCR C JNZ FINIT1 FINIT2: MVI M,0 ; TERMINATE LINE WITH NULL CALL FINIT3 ; CONVERT TO UPPER CASE CALL FPRS ; PARSE COMMAND LINE RZ ; RETURN IF NO COMMAND LINE ERROR LXI D,COMERR CALL COB ; ERROR MESSAGE TO CONSOLE MOV E,M PUSH B PUSH H CALL LO POP H POP B JMP IWRT3L IWRT3D: MVI E,0DH CALL LO MVI E,0AH CALL LO XRA A RET ; ; ------------------------------------- ; ; OPEN CHANNEL ; IOPEN: PUSH B ; BC POINTS TO ACCESS CODE CALL GFTAM,0 ; MEM(P) = 0 INX H ; P = P + 1 SHLD FNPTR1 ; IP = P LXI H,COMLIN ; P = ^COM SHLD FNPTR3 ; OP = ^CHANNEL 3 SPECIFICATION MVI C,',' CALL SCAN JZ FPRS2 ; JUMP IF ',' FOUND LXI H,FNLST SHLD FNPTR4 ; LP = ^'LST:' JMP FPRS3 FPRS2:HANNEL OFFSET XCHG LXI H,JCHAN+5 DAD D ; ADD CHANNEL OFFSET MOV A,M ; DEVICE CODE LHLD POINT RET ; ; --------------------------------- ; ; GET FILE TABLE POINTER ; GFTAB: LDA NCHAN ; GET CHANNEL NUMBER DCR A ADD A MOV E,A MVI D,0 MOV C,E DCX B ; BC = POINTER TO LINE LENGTH CALL LWRITE ; WRITE LINE ORA A RZ ; RETURN IF NO ERROR MVI A,1 RET ; ; SEND LINE TO CONSOLE ; IWRT2: DCX H MOV C,M ; GET LINE LENGTH INR C IWRT2L: DCR C JZ IWRT2D INX H MOV E,M LINE MOV A,M ; GET CHARACTER CALL FINIT5 ; CONVERT IF LOWER CASE MOV M,A JMP FINIT4 FINIT5: CPI 'A'+20H RC ; RETURN IF < 'a' CPI 'Z'+21H RNC ; RETURN IF > 'z' SUI 20H RET ; ; -------------------------------------- ; ; PARSE COLXI D,COMLIN-2 CALL CIB ; GET NEW COMMAND LINE LXI H,COMLIN-1 MOV E,M ; GET LINE LENGTH MVI D,0 INX H DAD D JMP FINIT2 FINIT3: LXI H,COMLIN-1 MOV C,M ; LENGTH OF COMMAND LINE INX H INR C FINIT4: DCR C RZ ; RETURN IF AT END OFB ; HL = FILE TABLE POINTER PUSH H CALL FNAME ; DE = FILE NAME POINTER POP H POP B RZ ; RETURN UNLESS DISK DEVICE CALL DOPEN ; OPEN FILE ORA A RZ ; RETURN IF NO ERROR MVI A,1 ; *** *** ERROR MESSAGE RET ; ; -------------------- MVI M,0 ; MEM(P) = 0 INX H ; P = P + 1 SHLD FNPTR4 ; LP = ^CHANNEL 4 SPECIFICATION FPRS3: LHLD FNPTR1 MVI B,1 CALL XDEVC ; LU(1) = XUNIT(IP) ORA A JZ FPRS8 ; ERROR IF NUL: SPECIFIED CPI 3 JZ FPRS8 ; ERROR IF LST: SPECIFIED LHLD FN LXI H,FTABP DAD D MOV A,M INX H MOV H,M MOV L,A RET ; ; ------------------------------------- ; ; GET FILE NAMES FROM COMMAND LINE ; FINIT: LXI D,80H LXI H,COMLIN-1 LDA 80H INR A MOV C,A ; # OF CHARACTERS FINIT1: LDAX D MOV PUSH B PUSH H CALL CO POP H POP B JMP IWRT2L IWRT2D: MVI E,0DH CALL CO MVI E,0AH CALL CO XRA A ; NO ERROR RET ; ; SEND LINE TO LIST DEVICE ; IWRT3: DCX H MOV C,M ; GET LINE LENGTH INR C IWRT3L: DCR C JZ IWRT3D INX HMMAND LINE ; FPRS: LXI H,COMLIN ; P = ^COM MVI C,'=' CALL SCAN JZ FPRS1 ; JUMP IF '=' FOUND LXI H,COMLIN SHLD FNPTR1 ; IP = ^COM LXI H,FNCON SHLD FNPTR3 ; OP = ^'CON:' LXI H,FNLST SHLD FNPTR4 ; LP = ^'LST:' JMP FPRS3 FPRS1: MVI DCLOSE ; CLOSE FILE ORA A RZ ; RETURN IF NO ERROR MVI A,1 RET ICNT3: XRA A ; SET OPERATION STATUS = 0 RET ; ; ------------------------------------ ; ; GET BUFFER POINTER & DEVICE CODE NUMBER ; HL A ; GBPDEV: LHLD CHOFF ; RECALL C------------------ ; ; CLOSE CHANNEL ; ICNTL: CALL GBPDEV ; HL - BUFFER POINTER CPI 1 ; A - DEVICE CODE JNZ ICNT3 ; JUMP UNLESS 1 - DISK DEVICE LXI H,JCHAN+6 DAD D MVI M,1 ; SET STATUS CLOSED CALL GFTAB ; HL = FILE TABLE POINTER CALLA,M CMP C RZ ; RETURN IF SEARCH SUCCESSFUL ORA A JZ SCAN1 ; JUMP IF END OF STRING INX H JMP SCAN SCAN1: INR A ; Z=0 - SEARCH FAILS RET ; ; ------------------------------------- ; ; GET FILE NAME POINTER FOR OPEN ; FNAME: CALL GDLINE, WRITE LINE, GENERAL CLOSE ; ; 3. ALLOW THE FOLLOWING FOR FILE NAMES: ; CON: - CONSOLE IN/OUT ; RDR: - READER IN ; PUN: - PUNCH OUT ; LST: - LISTING OUT ; ; ; TO OPEN DISK FILE ; ERROR IF FILE ALREADY OPEN ; ERROR IF BAODE POINT: DS 2 ; BUFFER POINTER NCHAN: DS 1 ; STORAGE FRO CHANNEL NUMBER LEN: DS 1 ; LINE LENGTH CHOFF: DS 2 ; CHANNEL TABLE OFFSET ; IACCE: DB 1 ; READ ACCESS CODE OACCE: DB 3 ; WRITE ACCESS CODE WITH DELETE FTABP: DW FTAB1 DW FTAB2 DW FTAB JZ XDEVC4 ; JUMP IF , = OR NULL FOUND PUSH H LXI D,XDVTBL-2 ; SPECIAL DEVICE CODE TABLE XDEVC2: INX D XDEVC1: INX D XDEVC0: LDAX D MOV C,A CPI 1 JZ XDEVC3 ; JUMP IF END OF TABLE POP H PUSH H INX D LDAX D INX D CMP M JDITIONS ; ;DREV EQU 20H ; 08/17/78 R. CURTISS INITIAL CODING ; ;DREV EQU 15H ; 07/26/78 R. CURTISS BWRITE - MVI A,0 JNZ ; ;DREV EQU 14H ; 07/25/78 R. CURTISS OPEN- NR=0 ; ;DREV EQU 13H ; 07/25/78 R. CURTISS FIX ERROR IN READ ; AND OTHER CH-- ; MCHOFF: DCR B ; COMPUTE CHANNEL OFFSET MOV A,B ; FOR TABLE LOOKUP RLC ; KCH = (JCH-1)*6 ADD B RLC MOV E,A MVI D,0 RET ; ; ------------------------------------- ; ; CONSOLE I/O ; BDOS EQU 0005H CIB: MVI C,10 CALL BDOS EVIC ; GET DEVICE CODE CPI 1 JZ FNAME1 ; JUMP IF DISK DEVICE XRA A RET FNAME1: LDA NCHAN DCR A ADD A MOV E,A MVI D,0 LXI H,FNPTR ; FILE NAME POINTER TABLE DAD D MOV E,M INX H MOV D,M MVI A,1 ORA A RET GDEVIC: LHLD C'STAGE2.CH2',0 FNNUL: DB 'NUL:',0 FNCON: DB 'CON:',0 FNLST: DB 'LST:',0 DB 128,0 COMLIN: DS 129 ; STORAGE FOR COMMAND LINE COMERR: DB 0DH,0AH,'>>>>> COMMAND ERROR - REENTER' DB 0DH,0AH,'$',0 ; ; 3 DW FTAB4 FTAB1: DB 0,0,0,'1' ; CHAN 1 FILE TABLE DS 33+128 FTAB2: DB 0,0,0,'2' DS 33+128 FTAB3: DB 0,0,0,'3' DS 33+128 FTAB4: DB 0,0,0,'4' DS 33+128 FNPTR: FNPTR1: DS 2 FNPTR2: DW FNCH2 FNPTR3: DS 2 FNPTR4: DS 2 FNCH2: DB NZ XDEVC2 ; JUMP IF NO MATCH INX H LDAX D INX D CMP M JNZ XDEVC1 ; JUMP IF NO MATCH INX H LDAX D INX D CMP M JNZ XDEVC0 ; JUMP IF NO MATCH INX H ; TABLE MATCH FOUND MVI A,':' CMP M JZ XDEVC3 ; JUMP IF COLON MVI C,1 ; DANGES ; ;DREV EQU 12H ; 07/01/78 R. CURTISS FIX ERRORS ; ;DREV EQU 11H ; 07/01/78 R. CURTISS INITIAL CODING ; ; CP/M DISK I/O PACKAGE ; 1. INITIAL IMPLEMENTATION ; OPEN, CLOSE, READ BYTE, WRITE BYTE ; ; 2. NEXT STAGE OF DEVELOPMENT ; READ RET COB: MVI C,9 CALL BDOS RET CO: MVI C,2 CALL BDOS RET LO: MVI C,5 CALL BDOS RET ; ; ------------------------------------ ; ; STORAGE ; JCHAN: DS 6*MAXCH+1 ; WORKING STORAGE FOR I/O TABLE JOP: DS 1 ; STORAGE FOR OPERATION CHOFF ; CHANNEL TABLE OFFSET LXI D,JCHAN+5 DAD D MOV A,M RET ; ; -------------------------------------- ; ; HL - POINTER TO FILE NAME ; B - CHANNEL NUMBER ; A - DEVICE CODE NUMBER ; XDEVC: CALL SKIPB ; SKIP BLANKS MVI C,0 ; NULL DEVICEDREV EQU 24H ; 06/13/79 R. CURTISS "," FOR DELIMITER ALSO ;DREV EQU 23H ; 06/10/79 R. CURTISS DCLOSE XRA A, NOT IF READ ;DREV EQU 22H ; 08/19/78 R. CURTISS DEF. DMA = 80 AFTER ; READS AND WRITES ;DREV EQU 21H ; 08/19/78 R. CURTISS GCLOSE ADL' DB 2,'CON' DB 2,'TTY' DB 2,'CRT' DB 2,'KBD' DB 3,'LST' DB 3,'LPT' DB 1 ; ; SKIPB: MOV A,M ORA A RZ SUI ',' RZ MOV A,M SUI '=' RZ MOV A,M CPI ' ' RNZ INX H JMP SKIPB ; ; ---------------------------------ISK DEVICE ASSUMED XDEVC3: POP H ; RESTORE STACK XDEVC4: PUSH B ; B - CHAN # C - DEVICE CODE # CALL MCHOFF ; MAKE CHANNEL OFFSET POINTER POP B LXI H,JCHAN+5 DAD D MOV M,C ; JCHAN(CH+5) = DEVICE CODE MOV A,C RET ; ; XDVTBL: DB 0,'NUD FILE NAME ; SELECT ( ACCESS ) ; ( 1 = READ ) CONTINUE ; ( 3 = WRITE ) ; ACCESS = 2 ; DELETE FILE IF PRESENT ; CREATE FILE ; ERROR IF NO DIRECTORY SPACE ; FIN ; ( 2 = WRITE ) ; ERROR IF FILE IS PRESENT ; CREATE FILE ; ERROR IFATION STATUS ; (Z) = CONDITION OF (A) ; GCLOSE: LDA LSIZE ; RECALL OPEN FILE COUNT ORA A RZ ; RETURN IF LIST IS EMPTY LXI H,FLIST ; GET FIRST FILLE TABLE POINTER MOV E,M INX H MOV D,M XCHG CALL DCLOSE ; CLOSE AND DELETE FILE FROM : ; (HL) POINTS TO FILE TABLE ORIGIN ; ; OUTPUTS: ; (A)=(HL)= OPERATION STATUS ; (Z) = CONDITION OF (A) ; DCLOSE: SHLD FTABLE ; SAVE FILE TABLE POINTER MOV A,M ; GET ACCESS CODE FROM FILE TABLE CPI 2 JNZ CLOSE1 ; JUMP IF NOT OPRATING SYSTEM DB DREV ; PUT REVISION NUMBER IN CODE DOPEN: SHLD FTABLE ; SAVE FILE TABLE POINTER MOV A,M ; GET ACCESS CODE FROM FILE TABLE CPI 0 JNZ ERR ; JUMP IF FILE ALREADY OPEN LDAX B ; GET OPEN ACCESS CODE STA ACCESS LHLDTER ANI 7FH ; MSB SHOULD BE 0 BUT BE SAFE RZ ; RETURN IF BUFFER IS EMPTY (Z)=1 LXI D,BUFF+127-2 ; -2 FOR 2 (INX HL) ABOVE DAD D ; (HL) POINTS TO LAST BUFFER BYTE CMA ADI 128+1 ; PAD COUNT = 128 - POINTER CLOSE6: MVI M,1AH ; PAD BUFFER WID MVI M,0 ; NEXT RECORD NUMBER IN FCB CALL GCLADD ; ADD FILE TABLE TO OPEN LIST LHLD FTABLE ; RECALL FILE TABLE POINTER LDA ACCESS MOV M,A ; SET ACCESS CODE IN FILE TABLE INX H XRA A MOV M,A ; SET STATUS TO ZERO (NORMAL) INX H NO DIRECTORY SPACE ; FIN ; ( OTHER ) ERROR ILLEGAL ACCESS CODE ; FIN ; OPEN FILE ; ERROR IF NOT PRESENT ; STATUS = 0 NORMAL ; POINTER = 0 BUFFER EMPTY ; FIN ; ; INPUTS: ; (HL) POINTS TO FILE TABLE ORIGIN ; (DE) POINTS TO FI ERR ; JUMP IF INVALID ACCESS CODE CLOSE2: CALL GCLREM ; REMOVE FILE TABLE FROM OPEN LIST LHLD FTABLE ; RECALL FILE TABLE POINTER XRA A MOV C,M ; GET ACCESS CODE MOV M,A ; ACCESS = 0 - FILE NOT OPEN INX H MOV M,A ; STATUS = 0 - NORMAL EN FOR WRITE CALL CLOSE4 ; OUTPUT LAST BUFFER IF NOT EMPTY JZ CLOSE2 ; JUMP IF NO WRITE ERROR PUSH PSW ; SAVE ERROR CONDITION CALL CLOSE2 ; CLOSE THE FILE POP PSW JMP ERR CLOSE1: ORA A JZ RETURN ; JUMP IF ALREADY CLOSED CPI 1 JNZ FTABLE ; RECALL FILE TABLE POINTER LXI B,FCBOFF ; FCB OFFSET IN FILE TABLE DAD B CALL GETNAM ; GET FILE NAME JNZ ERR ; JUMP IF NAME ERROR LDA ACCESS DCR A JZ OPEN6 ; JUMP IF READ ACCESS DESIRED CPI 2 JNZ OPEN2 ; JUMP IF NOT WRITE WITH CONTROL Z DCX H DCR A JNZ CLOSE6 CALL WRITE2 ; OUTPUT LAST BUFFER RET ; (Z)=1 IF WRITE IS OK ; ; ; TO CLOSE ALL OPEN FILES ; FOR EACH OPEN FILE ; CLOSE FILE ; FIN ; FIN ; ; INPUTS: ; NONE ; ; OUTPUTS: ; (A)=(HL)= OPERMOV M,A ; SET BUFFER POINTER TO ZERO JMP RETURN ; ; ; TO CLOSE FILE ; OUTPUT LAST BUFFER IF OPEN FOR WRITE ; ERROR IF ACCESS < 1 OR > 2 ; CLOSE FILE IF OPEN FOR WRITE ; ERROR IF NOT PRESENT ; ACCESS = 0 ; BUFFER POINTER = 0 ; FIN ; ; INPUTLE NAME STRING ; (BC) POINTS TO ACCESS CODE ; ; OUTPUTS: ; (A)=(HL)= OPERATION STATUS ; (Z) = CONDITION OF (A) ; ; FCBOFF EQU 4 ; FCB OFFSET IN FILE TABLE BUFF EQU 37 ; BUFFER OFFSET IN FILE TABLE BDOS EQU 0005H ; ENTRY POINT TO OPE INX H MOV M,A ; BUFFER POINTER = 0 DCR C JZ RETURN ; JUMP IF OPEN FOR READ MVI C,16 CALL BDOS1 ; CLOSE FILE CPI 255 JZ ERR ; JUMP IF FILE NOT PRESENT XRA A ; NO ERROR JMP RETURN CLOSE4: INX H INX H MOV A,M ; GET BUFFER POIN PRESENT OPEN4: MVI C,22 CALL BDOS1 ; CREATE FILE CPI 255 JZ ERR ; JUMP IF NO DIRECTORY SPACE OPEN6: MVI C,15 CALL BDOS1 ; OPEN FILE CPI 255 JZ ERR ; JUMP IF NOT PRESENT LHLD FTABLE ; RECALL FILE TABLE POINTER LXI D,FCBOFF+32 DAD TH DELETE STA ACCESS ; ACCESS = 2 MVI C,19 CALL BDOS1 ; DELETE FILE IF PRESENT JMP OPEN4 OPEN2: CPI 1 JNZ ERR ; JUMP IF INVALID ACCESS CODE MVI C,17 CALL BDOS1 ; CHECK TO SEE IF FILE IS PRESENT CPI 255 JNZ ERR ; JUMP IF FILE ISLIST JMP GCLOSE ; ; ; ADD FILE TABLE TO OPEN FILE LIST ; GCLADD: LDA LSIZE ; GET OPEN FILE COUNT CPI LMAX ; FILE LIST MAX SIZE JNC GCLA9 ; JUMP IF LIST IS FULL INR A STA LSIZE ; LSIZE = LSIZE + 1 DCR A ADD A ; A = A*2 MOV E,A MVI D (HL) POINTS TO FILE TABLE ORIGIN ; (DE) POINTS TO DATA BYTE STORAGE ; ; OUTPUTS: ; (A)=(HL)= OPERATION STATUS ; (Z) = CONDITION OF (A) ; ((DE)) = DATA BYTE RETURNED ; BREAD: SHLD FTABLE ; SAVE FILE TABLE POINTER XCHG SHLD OR READ INX H MOV A,M ; GET STATUS CODE ORA A JNZ ERR ; JUMP IF NOT NORMAL INX H ; (HL) POINTS TO BUFFER POINTER SHLD BPOINT ; SAVE IT LREAD1: CALL LREAD5 ; GET NEXT BYTE FROM DISK JNZ LREAD2 ; JUMP IF EOL,EOF,ERR CALL LREAD8 ; STOIST MOV A,M INX H XRA E MOV B,A MOV A,M INX H XRA D ORA B JNZ GCLR1 ; JUMP IF NO MATCH MOV D,H MOV E,L DCX D DCX D GCLR2: DCR C JZ GCLR8 ; JUMP IF END OF LIST MOV A,M STAX D INX H INX D MOV A,M STAX D ; LIETURN LREAD6: MVI A,255 ; END OF FILE LREAD7: ORA A ; END OF LINE RET ; ; STORE NEXT BYTE IN LINE ; LREAD8: INR C DCR C RZ ; RETURN IF LINE BUFFER FULL LHLD LPOINT ; RECALL LINE BUFFER POINTER MOV M,A INX H SHLD LPOINT DCR C FILE TABLE POINTER XCHG SHLD LPOINT ; SAVE LINE POINTER LXI H,DBYTE SHLD DATA ; DATA RETURN POINTER MOV H,B MOV L,C MOV E,M INX H MOV D,M ; (DE) POINTS TO 3RD ARG XCHG MOV C,M ; (C) HOLDS MAX LINE LENGTH MOV A,C STA CMAX ;,0 LXI H,FLIST DAD D ; (HL) POINTS TO NEXT LIST ENTRY POS. XCHG LHLD FTABLE ; RECALL FILE TABLE POINTER XCHG MOV M,E INX H MOV M,D ; LIST(LSIZE) = FILE TABLE POINTER RET GCLA9: ; ****************** NEED EROR MESSAGE RET ; ; ; A JMP RETURN ; NORMAL RETURN ; ; GET NEXT BYTE ; LREAD5: LHLD BPOINT ; RECALL BUFFER POINTER POINTER PUSH B ; SAVE LINE SPACE COUNT CALL BRXXX ; GET NEXT BYTE FROM DISK POP B RNZ ; RETURN IF EOF,ERR LDA DBYTE ; GET BYTE JUST READ ANI 7RE BYTE INTO LINE JMP LREAD1 LREAD2: PUSH PSW ; SAVE READ STATUS LDA CMAX ; RECALL MAX CHARACTER COUNT SUB C LHLD ACTP MOV M,A ; RETURN ACTUAL CHARACTER COUNT POP PSW CPI 0DH ; CARRIAGE RETURN JNZ RETURN ; RETURN IF EOF OR ERR XRA ST(M-1) = LIST(M) INX H INX D ; M = M + 1 JMP GCLR2 GCLR8: LDA LSIZE DCR A STA LSIZE RET GCLR9: ; ****************** NEED ERROR MESSAGE RET ; ; ; TO READ A LINE ; ERROR IF ACCESS <> "READ" ; ERROR IF STATUS <> "NORMAL" ; I = 1 ; RET ; ; ; TO READ BYTE ; ERROR IF ACCESS <> "READ" ; ERROR IF STATUS <> "ZERO" ; IF ( BUFFER EMPTY ) ; GET NEXT BUFFER LOAD ; POINT = 0 ; RETURN IF "EOF" ; FIN ; GET NEXT BYTE FROM BUFFER ; POINT = POINT + 1 ; FIN ; ; INPUTS: ; SAVE MAX LINE LENGTH XCHG INX H MOV E,M INX H MOV D,M ; (DE) POINTS TO 4TH ARG XCHG SHLD ACTP ; SAVE POINTER FOR ACTUAL LENGTH LHLD FTABLE ; RECALL FILE TABLE POINTER MOV A,M ; GET ACCESS CODE CPI 1 JNZ ERR ; JUMP IF NOT OPEN FREMOVE FILE TABLE POINTER FROM OPEN FILE LIST ; GCLREM: LHLD FTABLE ; RECALL FILE TABLE POINTER XCHG LXI H,FLIST ; ORIGIN OF OPEN FILE LIST LDA LSIZE ; RECALL OPEN FILE COUNT MOV C,A INR C GCLR1: DCR C JZ GCLR9 ; JUMP IF END OF OPEN FILE LFH JZ LREAD5 ; IGNORE NULL CPI 0AH JZ LREAD5 ; IGNORE LINE FEED CPI 7FH JZ LREAD5 ; IGNORE RUBBOUT CPI 1AH ; CONTROL Z JZ LREAD6 ; JUMP IF END OF FILE CPI 0DH JZ LREAD7 ; JUMP IF CARRIAGE RETURN CMP A ; (Z)=1 RET ; NORMAL RE BUFFER ORIGIN ; (BC) POINTS TO PARAMETER LIST ; 3RD POINTS TO MAX CHARACTER COUNT (255 MAX) ; 4TH POINTS TO ACTUAL CHARACTER COUNT (255 MAX) ; ; OUTPUTS: ; (A)=(HL)= OPERATION STATUS ; (Z) = CONDITION OF (A) ; LREAD: SHLD FTABLE ; SAVE GET-NEXT-BYTE ; UNTIL ( EOL,EOF,ERR ) ; IF ( I <= MAX-CHARACTER-COUNT ) ; LINE(I) = BYTE ; I = I + 1 ; FIN ; GET-NEXT-BYTE ; FIN ; RETURN-ACTUAL-CHARACTER-COUNT ; FIN ; ; INPUTS: ; (HL) POINTS TO FILE TABLE ; (DE) POINTS TO LINDATA ; SAVE DATABYTE POINTER MVI M,1AH ; TENTATIVELY RETURN CONTROL Z XCHG MOV A,M ; GET ACCESS CODE CPI 1 JNZ ERR ; JUMP IF NOT READ ACCESS INX H MOV A,M ; GET STATUS CODE CPI 0 JNZ ERR ; JUMP IF NOT NORMAL INX H BRXXX: MOV A, CPI 2 ; END OF DISK RNZ ; RETURN IF ERROR (A)=1,>2 (Z)=0 LHLD FTABLE ; RECALL FILE TABLE POINTER INX H MVI A,255 ; END OF MEDIUM MOV M,A ; SET STATUS CPI 255 ; SET ZERO FLAG FOR NO ERROR RET ; (A)=255 (Z)=1 ; ; ; SCAN FILE NAME ; PUSH H CALL BWXXX ; WRITE CARRIAGE RETURN TO DISK POP H RNZ ; RETURN IF WRITE ERROR MVI B,0AH CALL BWXXX ; WRITE LINE FEED TO DISK RET ; ; ; TO WRITE BYTE ; ERROR IF ACCESS <> "WRITE" ; ERROR IF STATUS <> "ZERO" ; PUT BYTE INTO BUFFE IN BUFFER MOV A,M ; GET NEXT DATA BYTE LHLD DATA ; RECALL DATA RETURN POINTER MOV M,A ; RETURN DATA BYTE TO CALLER XRA A ; (A)=0 (Z)=1 JMP RETURN ; NORMAL RETURN READ4: MVI C,26 CALL BDOS2 ; SET DMA ADDRESS MVI C,20 CALL BDOS1,BUFF-2 ; -2 FOR 2 (INX HL) ABOVE DAD D ; (HL) = FTABLE+BUFF+POINT MOV M,B ; STORE DATA BYTE INTO BUFFER CPI 0 MVI A,0 ; NO ERROR JNZ RETURN ; JUMP IF BUFFER NOT FULL CALL WRITE2 ; WRITE BUFFER TO DISK JNZ ERR ; JUMP IF WRITE ERROR JE FILE TABLE POINTER MOV A,M ; GET ACCESS CODE CPI 2 JNZ ERR ; JUMP IF NOT OPEN FOR WRITE INX H MOV A,M ; GET STATUS CODE ORA A JNZ ERR ; JUMP IF NOT NORMAL INX H ; POINTS TO BUFFER POINTER LDAX B ; CHARACTER COUNT MOV C,A INRM ; GET BUFFER POINTER MOV E,A ; SAVE CURRENT POINTER INR A ANI 7FH MOV M,A ; POINTER = (POINTER + 1) MOD 128 MOV A,E ; GET CURRENT POINTER ORA A JNZ READ2 ; JUMP IF BUFFER NOT EMPTY CALL READ4 ; GET NEXT BUFFER LOAD JNZ ERR ; JUMP IFZ) = CONDITION OF (A) ; BWRITE: SHLD FTABLE ; SAVE FILE TABLE POINTER LDAX D ; GET DATA BYTE MOV B,A ; SAVE IN B MOV A,M ; GET ACCESS CODE CPI 2 JNZ ERR ; JUMP IF NOT WRITE ACCESS INX H MOV A,M ; GET STATUS CODE CPI 0 JNZ ERR ; R ; POINT = POINT + 1 ; IF ( BUFFER FULL ) ; WRITE NEXT BUFFER LOAD ; POINT = 0 ; FIN ; FIN ; ; INPUTS: ; (HL) POINTS TO FILE TABLE ORIGIN ; (DE) POINTS TO DATA BYTE STORAGE ; ; OUTPUTS: ; (A)=(HL)= OPERATION STATUS ; ( ; READ NEXT DISK RECORD PUSH PSW MVI C,26 LXI D,80H CALL BDOS ; RESTORE DMA ADDR TO DEFAULT POP PSW ORA A RZ ; RETURN IF OK (Z)=1 CPI 1 ; EOF RNZ ; RETURN IF ERROR (A)>1 (Z)=0 LHLD FTABLE ; RECALL FILE TABLE POINTER INX HMP RETURN WRITE2: MVI C,26 CALL BDOS2 ; SET DMA ADDRESS MVI C,21 CALL BDOS1 ; WRITE NEXT DISK RECORD PUSH PSW MVI C,26 LXI D,80H CALL BDOS ; RESTORE DMA ADDR. TO DEFAULT POP PSW ORA A RZ ; RETURN IF WRITE OK (A)=0 (Z)=1 C LWRIT1: DCR C JZ LWRIT2 ; JUMP IF END OF LINE PUSH H PUSH D PUSH B LDAX D ; GET NEXT DATA BYTE MOV B,A CALL BWXXX ; WRITE BYTE TO DISK POP B POP D POP H RNZ ; RETURN IF WRITE ERROR INX D JMP LWRIT1 LWRIT2: MVI B,0DH READ ERROR ORA A JNZ RETURN ; JUMP IF END OF FILE MVI E,0 ; CURRENT POINTER READ2: LHLD FTABLE ; RECALL FILE TABLE POINTER MVI D,0 ; (E) IS BUFFER POINTER DAD D LXI D,BUFF ; BUFFER OFFSET IN FILE TABLE DAD D ; (HL) POINTS TO NEXT BYTEJUMP IF NOT NORMAL INX H ; ; (HL) POINTS TO BUFFER POINTER ; (B) DATA BYTE FOR OUTPUT ; BWXXX: MOV A,M ; GET BUFFER POINTER MOV E,A ; SAVE CURRENT POINTER INR A ANI 7FH MOV M,A ; POINTER = (POINTER+1) MOD 128 MVI D,0 DAD D LXI DI) ; FIN ; FIN ; ; INPUTS: ; (HL) POINTS TO FILE TABLE ; (DE) POINTS TO LINE BUFFER ORIGIN ; (BC) POINTS TO LINE LENGTH IN BYTES (255 MAX) ; ; OUTPUTS: ; (A)=(HL)= OPERATION STATUS ; (Z) = CONDITION OF (A)