.NLIST TTM,BEX,CND .ENABL LC .TITLE SPELLING CHECKER .IDENT /V2.03/ ; SSSSSS PPPPPPP EEEEEEE LL LL ; SS SS PP PP EE LL LL ; SS PP PP EE LL LL ; SSSSSS PPPPPPP EEEEE LL LL ; SS PP EE LL LL ; SS SS PP EE LL LL ; SSSSSS PP EEEEEEE LLLLLLL LLLLLLL ; ; Original: DECUS RT-11 SIG tape, Warwick 1981. ; Author: Dave Walesby ; ; Revising Author: C J Doran ; Sira Ltd., South Hill, Chislehurst, Kent, BR7 5EH, England. ; ; N.B.B. All enhancements have been made to, and tested on, RSX-11M ONLY at ; present. Some nominal attempt has been made to keep the RT-11 portions ; of the code updated too, but it is most unlikely that this code will ; still work under RT-11 without substantial debugging!!!! ; ; MODIFICATIONS RECORD ; ==================== ; V2.01 28-May-82 CJD ; Add conditional code for RSX-11M. ; Add support for languages: BCPL, C, Pascal, RATFOR, SAL assembly language. ; Update RUNOFF checker to recognise ';' as command terminator. ; Correct bug in FORTRAN file processing -- only recognise C immediately ; after newline (used to select first C on line). ; Correct bug in RTL2 processing -- trailing % should be treated as ; word terminator. ; Report total and queried words counts. ; Correct bug that word of length <= MINLEN at end of line cancelled ; CR/LF/FF flag. ; If memory full, continue, changing to print every & don't load, as ; manual says, instead of exiting. ; ; V2.02 1-Jul-82 CJD ; Add /IU switch -- ignore words wholly in upper case. ; When inserting in dictionary, move memory by words, not bytes, if ; possible, to increase speed. ; ; V2.03 18-Aug-83 CJD ; Add /IP switch -- don't complain about embedded punctuation. ; Add /QU switch -- ask whether to load unknown words. ; Print dots during dictionary load to show something's happening! ; Correct bug that a word beginning zz caused a consistency check failure ; -- if loading FSTLET+52., note that 1 was added to it on startup. ; Use SOB in dictionary move operations -- should be 33% faster. ; Default to TI: for list file if no '=', instead of complaining. ; Exit via JMP $EXST, which works on systems without EXST$, and may be ; in FCSRES. ; Correct bug that dictionaries are ignored if switches appear on I/P file. ; Attach to TI: so control/O will work. ; Note that GTSK$ returns size of task, which is 1+max usable address, ; so decrement G.TSTS for top (covers special case that 32k task ; returns size 0). Also check CMP for overflow when checking for ; extend near top of such a task, which would wrap-around on insert. ; Exit ANA immediately if memory overflows on dictionary load. ; Check for illegal /IG:<=0, which crashes search, default it to 1. ; Compute free space as 177777-last used, since can extend that far. ; Use AUXSWD bits instead of words UPLWM,NOPLIN,NOUPPR. ; Double-buffer dictionary reads. ; ; ASSEMBLY OPTIONS ; ================ ; (For RSX-11M the following symbols can be set by using RSXMC.MAC as ; an assembly prefix file.) ; ; Define one and only one of the following symbols selecting operating system: ;RT11=1 ; Enable this definition for RT-11 R$$11M=1 ; Enable this definition for RSX-11M ; ; Define the following symbol if EIS instructions are available: M$$EIS=1 ; OK to use MUL, SOB, ASH .IF DF R$$11M ; Define the following symbol if exit status is to be returned. P$$OFF=0 ; Parent-offspring tasking supported (for EXST$) ; Define the following symbol if the Extend Task directive can be used: E$$XPR=0 ; Extend task directive (EXTK$) ; Define the following if Get Partition/Get Task Parameters are available: G$$TPP=0 ; Get Partition Parameters Directive (GPRT$) G$$TTK=0 ; Get Task Parameters Directive (GTSK$) ; If any of the last three above is not available, the following symbol must be ; set to give a fixed dictionary space in the task image: .IIF NDF E$$XPR!G$$TPP!G$$TTK,DICSPC=42000. ; Dictionary bytes ; Define the following if the Get Mapping Context directive is available: P$$GMX=0 ; Get Mapping Context Directive (GMCX$) ; Define the following symbol if terminal driver supports read-after-prompt T$$RPR=0 ; Read-after-prompt (IO.RPR) on terminal ; ; Define the following symbol if SPELL should double-buffer input during ; dictionary loading (when there is only one file open, and a spare FSR buffer ; is therefore free. Note that to take advantage of this option, the task ; must be built with ANSLIB or FCSMBF. DOUBUF=0 ; Double-buffer dictionary reads. ; .ENDC ; Define the following symbol if tabs may be used for positioning in multi-column ; errors listing. (OK for RSX, or RT-11 V3B or later.) AUTOHT=0 ; Hardware or drivers support horizontal tabs ; .IF DF RT11 ; Assemble and link as: ; .MACRO SPELL ; .LINK SPELL .ENDC .IF DF R$$11M ; Assemble as: ; >MAC SPELL,SPELL/-SP={LB:[200,200]RSXMC/PA:1,SY:}[g,m]SPELL ; ; Include RSXMC.MAC only if required to set R$$11M etc (see above). ; ; Task-build as: ; >TKB ; TKB>SPELL/-FP/-SE/MM/CP,SPELL/-SP=SPELL ; TKB>/ ; TKB>TASK=...SPE ; TKB>UNITS=4 ; TKB>ACTFIL=3 ; TKB>ASG=SY:1:2:3,TI:4 ; TKB>STACK=48 ; TKB>TASK=...SPE ; TKB>; Include next line if FCSRES available ; TKB>LIBR=FCSRES:RO ; TKB>; Set initial dictionary space -- enough for LB:[1,2]SPELL.WRD ; TKB>EXTTSK=21000 ; TKB>// .ENDC ; .IF DF RT11 .MCALL .PRINT,.CSIGEN,.WRITW,.READ,.EXIT,.TTYOUT,.GTLIN .MCALL .CLOSE,.QSET,.SETTOP,.WAIT,.LOOKUP,.FETCH ERRWRD =52 ; Word containing info on I/O failure ; Output string to TI:, LEN & CCTRL arguments are dummies, for RSX compatibility .MACRO TIMESG MESSAG,LENGTH,CC .PRINT MESSAG .ENDM TIMESG .ENDC .IF DF R$$11M .MCALL FCSMC$,QIOW$,DIR$,GTSK$,GPRT$S,GMCX$,GLUN$,GET$S,PUT$S,EXTK$S .MCALL CSI$,CSI$1,CSI$2,GCML$,GCMLB$,GCMLD$,CSI$SW,CSI$SV,CSI$ND FCSMC$ CSI$ GCMLD$ ; Check some assumptions about CSI control block offsets and info: .IIF NE C.TYPR, .ERROR C.TYPR ; C.TYPR incorrectly assumed to be 0 .IIF NE CS.INP-1, .ERROR CS.INP ; CS.INP incorrectly assumed to be 1 .IIF NE CS.OUT-2, .ERROR CS.OUT ; CS.OUT incorrectly assumed to be 2 ; Print message on TI: .MACRO TIMESG MESSAG,LENGTH,CC=#ALLMSG .IIF NB,MESSAG, MOV MESSAG,TIQIOW+Q.IOPL .IIF NB,LENGTH, MOV LENGTH,TIQIOW+Q.IOPL+2 .IF IDN,CC,#0 CLR TIQIOW+Q.IOPL+4 .IFF .IIF DIF,CC,ASLAST, MOV CC,TIQIOW+Q.IOPL+4 .ENDC DIR$ #TIQIOW .ENDM TIMESG .ENDC ; Call NUMBR1 to put unsigned number into string .MACRO NUMBER BINARY,ASCII .IIF NB,BINARY, MOV BINARY,%1 .IIF NB,ASCII, MOV ASCII,%0 JSR PC,NUMBR1 .ENDM NUMBER ; Load error message into %4,%5 and jump to error handler (if named). .MACRO ERROR MESSAG,LENGTH,ERRHND MOV MESSAG,%4 MOV LENGTH,%5 .IIF NB,ERRHND, JMP ERRHND .ENDM ERROR .MACRO DEFINE LABEL,LENGTH LABEL== TOTLEN+. TOTLEN= TOTLEN+ .ENDM DEFINE TOTLEN= 0 ; For macro expansion .IF NDF M$$EIS .MACRO SOB REG,LAB ; Replacement for SOB DEC REG BNE LAB .ENDM SOB .ENDC .IF DF E$$XPR ; Extend task size by DEST bytes, branch to LFAIL if can't be done. .MACRO MORMEM DEST,LFAIL ADD #63.,DEST ; Round up BIC #63.,DEST ; to next exact multiple of 32 words MOV DEST,-(SP) ; Save increment in bytes CLC ; Clear carry ROR DEST ; Do one rotate, divide by 2 & lose sign .IF DF M$$EIS ASH #-5,DEST ; Remainder can be done by arith shift .IFF .REPT 5 ; Remainder can be arithmetic shifts ASL DEST .ENDR .ENDC EXTK$S DEST ; Extend task MOV (SP)+,DEST ; Restore actual increment BCS LFAIL ; Trap extend task failure ADD DEST,MEMLIM ; OK, update limit pointer .ENDM MORMEM .ENDC ; E$$XPR MINFRE =1500. ; Default minimum free memory in bytes after system dic loaded MXWORD =30. ; Maximum length of word stored CR =15 LF =12 SPACE =40 FORM =14 HT =11 .IF DF RT11 ;Channels used: ; 0 Difference file ; 1 Concatenated dictionaries & file for checking ; 3 File for checking ; 4 Dictionary file ; 5 Dictionary file ; 6 Dictionary file ; 7 Dictionary file ; 8 Dictionary file ; 9 Users default dictionary DK:SPELL.WRD ; 10 System default dictionary SY:SPELL.WRD .ENDC .IF DF R$$11M ; LUNs used: GCLUN =1 ; Get command line processing INLUN =2 ; Input file OUTLUN =3 ; Output files DICLUN =3 ; and dictionary input TILUN =4 ; TI: BUFLEN=132. ; I/O buffer length STMSG='$ ; Carriage-control char for start of error message ENDMSG='+ ; Ditto to append end ALLMSG=SPACE ; Space when all in one .ENDC ; Definitions for CODE which control options and gives word state. ASK =4000 ; Ask whether to load unknown words TNGESS =400 ; Do not guess this word TNLOAD =200 ; Do not load this word DICT =100 ; Current file being processed is a dictionary NLOAD =20 ; User does not want errors loaded into dictionary, and ; every error is printed in difference file NGUESS =10 ; User does not want program to guess what errors are WRDBEG =2 ; Currently forming a word CHCRLF =1 ; Last character was a CR/LF/FF .PAGE ; This PSECT contains one-time startup code, which is overwritten after use. .PSECT TEMP,RW,D,REL TEMP=. .IF DF RT11 ; Switch processing subroutines SWTTAB: SWTA,SWTB,SWTC,SWTD,SWTE,SWTF,SWTG,SWTH,SWTI,SWTJ,SWTK,SWTL,SWTM SWTN,SWTO,SWTP,SWTQ,SWTR,SWTS,SWTT,SWTU,SWTV,SWTW,SWTX,SWTY,SWTZ ; All entered with %3=switch value (if any), ; %4->INROUT input processor address address ; %5->COMMENT characte(s) store SWTA: MOV #MACRO,@%4 ; AP120B uses MACRO routine MOV #'",@%5 ; Change comment char from ; to " RTS PC SWTB: BIS #IPBIT,AUXSWD ; Don't query embedded punctuation RTS PC ; Minimum length of words to consider SWTC: TST R3 ; Value must be greater than zero BLE 13$ ; Not so ignore switch CMP #MXWORD,R3 ; Greater than max BGT 12$ ; No so jump MOV #MXWORD-1,R3 ; Set to maximum -1 12$: MOV R3,MINLEN 13$: RTS PC SWTD: DEC FILE ; Dictionaries not wanted RTS PC SWTE: BIC #NLOAD,CODE ; All errors to be printed RTS PC SWTF: MOV #FORTRA,@%4 MOV #"!C,@%5 ; Comments start 'C' or '!' SWTG: RTS PC SWTH: .PRINT #HLPTXT ; HELP TST (SP)+ ; doesn't do any processing BR AGAIN SWTI: BIS #NGUESS,CODE ; Inhibit guessing SWTJ: MOV #C,@%4 ; C source file RTS PC SWTK: BIS #IUBIT,AUXSWD ; Don't check all-upper-case words RTS PC SWTL: MOV #RTL2,@%4 ; Pascal has RTL-2-type comments MOV #"{},@%5 ; but within { ... } RTS PC SWTM: MOV #MACRO,@%4 ; MACRO MOV #';,@%5 RTS PC SWTN: MOV R3,LINLEN ; Number of chars on line SWTO: RTS PC SWTP: BIC #WIBIT,AUXSWD ; Set flag for 3 errors per line RTS PC SWTQ: BIS #ASK,CODE ; Ask about each unknown word BR SWTE ; Go clear NLOAD to force insertion SWTR: MOV #RUNOFF,@%4 RTS PC SWTS: MOV R3,FRESPC ; Store free space req RTS PC SWTT: MOV #RTL2,@%4 ; Intercept with RTL2 routine MOV #"%%,@%5 RTS PC SWTU: BIS #UCBIT,AUXSWD ; Set bit to force upper case SWTV: RTS PC SWTW: MOV #MACRO,@%4 ; RATFOR is like MACRO MOV #'#,@%5 ; with comment line starting '#' RTS PC SWTX: MOV #NULL,@%4 ; Plain text needs no processing RTS PC SWTY: MOV #BCPL,@%4 ; BCPL is special RTS PC SWTZ: MOV #MACRO,@%4 ; SAL is like FORTRAN MOV #";*,@%5 ; Comments start ; or * (col 1 only) RTS PC ; ENTRY POINT ; =========== SPELL:: .QSET #QQQQ,#2 ; Queue space .PRINT #TTLE AGAIN: CLR FILE ; Flag indicates if default dicts reqd .CSIGEN #DEVS,#DEFLT,#0 MOV R0,FREE ; Store start of free space MOV (SP)+,R1 MOV #INROUT,%4 ; To save code, make a pointer to input filter MOV #COMMENT,%5 ; and comment character(s) area SWLOP: DEC R1 ; Sort out switches BMI SWITND CLR R3 MOV (SP)+,R2 BPL 43$ ; Jump if no value to switch MOV (SP)+,R3 43$: CMP %2,#'$ ; Break to ODT? BNE 44$ ; No, try other switches BPT ; Yes, break and continue ; Virtually all letters are used, so use switch char as a JSR table index. 44$: CMP #'A,%2 ; Convert to letter BLO SWLOP ; Ignore if not a letter CMP %2,#'Z ; Check upper bound too BHI SWLOP ASL %2 ; OK, double code JSR PC,@SWTTAB-'A-'A(%2) ; and jump according to switch SOB %1,SWLOP ; Do all switches SWITND: TST FILE BNE 1$ ; Are default files required? .ENDC .IF DF R$$11M SPELL:: MOV SP,SPSAVE ; Save stack pointer TST #.ODTL1 ; Is ODT built in? BNE 10$ ; Yes, allow /BK switch MOV #NOP,BREAK ; No, change it to a NO-OP 10$: .IF DF G$$TPP&G$$TTK ; Find out from the system how much dictionary space is available above ; end of task. DIR$ #GTSK ; Fetch task parameters BCS 25$ ; Treat failure as "no memory" MOV GTKBUF+G.TSTS,%0 ; Fetch size of task DEC %0 ; Size-1 is highest allowed address GPRT$S #GTKBUF+G.TSPN,#GPTBUF ; Get partition parameters BCS 25$ ; (for unmapped system). Trap error again ADD $DSW,%0 ; Add partition base to top of task MOV %0,MEMLIM ; Save memory top MOV $DSW,MEMMAX ; Save $DSW for the moment SUB FREE,%0 ; Subtract free space start address SUB #MINFRE,%0 ; Require at least default MINFRE .IF DF E$$XPR BHIS 15$ ; OK, continue NEG %0 ; Not enough, see how much extra needed MORMEM %0,25$ ; and ask for it. Trap to 25$ if error .IFF BLO 25$ ; Not enough, error .ENDC 15$: TST MEMMAX ; If $DSW from GPRT$=0, this system is mapped .IF NDF P$$GMX BEQ 20$ ; So max available address=65536=0+carry(ignored) .IFF BNE 18$ ; <>0 means unmapped DIR$ #GMCX ; Mapped. Get mapping context BCS 20$ ; Ignore if it fails ; Find the lowest <>0 window base address. This will be 0 if FCSRES is not ; loaded, and probably 160000 if it is. This is then the highest address we ; can use + 1, for the purposes of computing the free space in the dictionary. MOV #GMCBUF,%0 ; Address 1st WDB vector 16$: TST @%0 ; Reached last if -ve BMI 20$ ADD #16.,%0 ; Point to next TST W.NBAS-16.(%0) ; Was base address 0? BEQ 16$ ; Yes, try next TST MEMMAX ; No, is current max memory 0? BEQ 17$ ; Yes, replace max memory value CMP W.NBAS-16.(%0),MEMMAX ; No, is it < current maximum? BHIS 16$ ; No, try next 17$: MOV W.NBAS-16.(%0),MEMMAX ; Yes, store new value BR 16$ ; Look at next entry .ENDC 18$: MOV GPTBUF+G.PRPS,%0 ; Else it is partition size ADD GPTBUF+G.PRPB,%0 ; + base, given in units of 64 bytes .IF DF M$$EIS ASH #5,%0 ; Convert to a byte address .IFF .REPT 5 ; Convert to a byte address ASL %0 .ENDR .ENDC MOV %0,MEMMAX ; Save top address .IFF MOV #DICST+DICSPC,MEMMAX ; Top of dictionary is fixed at assembly time .ENDC 20$: FINIT$ ; All OK, Initialise FCS DIR$ #GLUN ; Get TI: device information MOV GLUBUF+G.LUNA,TIDEV ; Save device name (TT or VT) MOVB GLUBUF+G.LUNU,TIUNIT ; and unit for later DIR$ #ATTACH ; Attach to TI:, so ^O will work JMP NXTCMD ; Jump to RO PSECT for re-usable code 25$: TIMESG #NOMEM,#NOMEML ; No memory allocated .IIF DF P$$OFF, MOV #EX$SEV,%0 ; Set to severe error JMP $EXST ; Return to CLI GTSK: GTSK$ GTKBUF ; Get task parameters DPB GLUN: GLUN$ TILUN,GLUBUF ; Get TI: LUN parameters DPB GMCX: GMCX$ GMCBUF ; Get mapping context DPB GTKBUF: .BLKW 16. ; Params returned here GPTBUF: .BLKW 3. ; Similar buffer for GPRT$ GLUBUF: .BLKW 6. ; and for GLUN$ GMCBUF: .REPT 65. ; WDB vectors for GMCX$ .WORD 0 .ENDR ATTACH: QIOW$ IO.ATT,5,5,,IOSTAT ; Attach to TI: NOMEM: .ASCII "SPE -- *SEVERE ERROR*-No memory for dictionaries" NOMEML=.-NOMEM .PSECT NXTCMD: MOV SPSAVE,SP ; Restore SP MOV #INCHAR,INTCPT ; Reset get character routine BIC #HEBIT!BKBIT,SWWRD ; Don't latch /HE or /BK switches BIT #LABIT,SWWRD ; Other switches latched? BNE GETCMD ; Yes, don't reset defaults CLR SWWRD ; No, set default switches -- general, CLR AUXSWD ; auxiliary -- /WI/-IP/-UC/-IU CLR LANG ; and language (0 = according to filetype) MOV #177777,COMMENT ; Unknown comment characters MOV #^RRNO,DEFTYP ; Default filetype .RNO MOV #BUFLEN,LINLEN ; Default BUFLEN chars max per line MOV #1,MINLEN ; Consider words of all lengths > 1 letter MOV #MINFRE,FRESPC ; Set free space requirement GETCMD: GCML$ #GC ; Get command line BCC CMDIN ; Branch if OK CMPB GC+G.ERR,#GE.EOF ; Control/Z? BNE CMDERR ; No, report error EXIT: .IIF DF P$$OFF, MOV EXSTAT,%0 ; Fetch exit status JMP $EXST ; Exit with status (or without) ; Error handlers. ; File I/O errors. %0->FDB. OPNERR: ERROR #OPNERM,#OPNERL ; Enter here if file open error ; %4,%5 contain error message string pointer/length, as below. FILERR: MOVB F.ERR(%0),%1 ; Fetch error number MOV #^B1011100001010,%2 ; Load conversion flags TSTB F.ERR+1(%0) ; Is it FCS or DSW error? BPL 1$ ; +ve means FCS NEG %1 ; Change error code sign to + if DSW ADD #^B100000000000,%2 ; and field width to 3 for leading space 1$: MOV %4,%0 ; Load error number address, ADD %5,%0 ; 4 bytes from end of string SUB #4,%0 JSR PC,$CBTA ; Convert to ASCII BR FATAL ; File errors are fatal CMDERR: ERROR #CMDERM,#CMDERL ; Load "Command error" message ; Enter here with fatal error message address in %4, length in %5, to ; print error and return for a new command. FATAL: TIMESG #ERRORM,#ERRORL,#STMSG ; Print "SPE -- *ERROR*-" TIMESG %4,%5,#ENDMSG ; and reason .IIF DF P$$OFF, MOV #EX$ERR,EXSTAT ; Set error exit status CLOSE$ #INFDB ; Close any open files CLOSE$ #OUTFDB BR NXTCMD ; Try again CMDIN: CSI$1 #CSIBLK,GC+G.CMLD+2,GC+G.CMLD ; Pre-process command line BCS CMDERR ; Trap syntax error TST CSIBLK+C.CMLD ; Blank command line? BEQ GETCMD ; Yes, fetch another ; Call CSI2 for all files to accumulate all switches, and test for ; CSI syntax errors. MOVB #CS.OUT,@%0 ; Start with outputs (C.TYPR = 0) MOV #SWTAB,C.SWAD(%0) ; Set up switch table CLRB INBUF ; Clear /CC value ASCII buffers CLRB INBUF+6 CLRB FILES ; Clear files present flag 10$: CSI$2 ; Fetch switches BCS CMDERR ; Trap error BITB #CS.WLD,C.STAT(%0) ; No wildcards allowed BNE CMDERR ; Reject if found BISB C.STAT(%0),FILES ; OR all bits into files present flag BITB #CS.MOR,C.STAT(%0) ; Any more files of this type? BNE 10$ ; Yes, go fetch next DECB @%0 ; No, change CS.OUT (2) to CS.INP (1) BEQ 20$ ; So just done if we get 0 BITB #CS.EQU,C.STAT(%0) ; If '=', there are inputs too BNE 10$ ; Go and do them ; Process accumulated switches. 20$: MOV SWWRD,%3 ; Get switch word BPL PROSWT ; If break bit (15) set, call ODT BREAK: BPT ; (BPT becomes NOP if ODT not built in) ; Process switches. First the language ones (mutually exclusive). PROSWT: MOV #LNGTAB-6,%2 ; Address lookup table MOV LANG,%1 ; Fetch language switch keyword BEQ GENSWT ; None, will set by input filetype later 10$: ADD #6,%2 ; Advance table pointer ASR %1 ; Shift out a bit BCC 10$ ; Keep looking if it was clear BNE CMDERR ; Shifted out a bit, error if any others set 20$: MOV (%2)+,DEFTYP ; Language found, load default filetype, MOV (%2)+,INROUT ; character processor routine, MOV #COMMENT,%5 ; Address COMMENT characters BIT #CCBIT,%3 ; User-specified comment char(s)? BNE 30$ MOV @%2,@%5 ; No, use defaults BR GENSWT 30$: MOV #INBUF,%0 ; Yes, Address first character argument TSTB @%0 ; Was there one? BEQ GENSWT ; No, keep what we had last time JSR PC,GETCCH ; Get ASCII byte or octal value INC %5 ; Argument will go into hi byte MOVB #377,@%5 ; Assume no second character MOV #INBUF+6,%0 ; Address string JSR PC,GETCCH ; and complete character pair ; Deal with other switches not handled completely by CSI. GENSWT: BIT #HEBIT,%3 ; Help required? BEQ 30$ ; No, branch TIMESG #HLPTXT,#HLPLEN ; Yes, print help text 30$: BIT #LEBIT,%3 ; Line length set? BEQ 50$ ; No, continue CMP LINLEN,#BUFLEN ; Yes, >= buffer length? BLOS 50$ ; Yes, OK MOV #BUFLEN,LINLEN ; No, clip to buffer length 50$: BIT #IGBIT,%3 ; Minimum length bit set? BEQ 60$ ; No, branch CMP MINLEN,#MXWORD ; Yes, did length exceed maximum word length? BLE 55$ ; No, OK MOV #MXWORD-1,MINLEN ; Yes, clip it to maximum-1 55$: TST MINLEN ;V2.03 Test for value <=0 BGT 60$ ;V2.03 OK if >=1 MOV #1,MINLEN ;V2.03 Make it 1 if less 60$: TSTB FILES ; Any files given? BNE 65$ ; Yes, process them JMP NXTCMD ; No, only switches, get another line 65$: CLR FILEN ; Zero dictionary file total blocks BIT KEEPD,%3 ; Keep old dictionaries? BNE 5$ ; Yes, skip reset code TSTB %3 ; No, load default dics? (DDBIT is bit 7) BPL 70$ ; Yes if bit CLEAR, go see if needed CLR GOTDD ; No if bit SET, say haven't got dictionaries BR 1$ ; Skip OPDEF to reset dictionary pointers 70$: TST GOTDD ; Got default dics unchanged from last time? BNE 5$ ; Yes, don't reload .ENDC BIS #DICT,CODE ; Set dictionary flags JSR PC,OPDEF ; Get sizes of default dictionaries 1$: CLR NOWRDS ; Clear dictionary word count MOV FREE,R0 MOV #FSTLET,R2 ; Addresses of first letters MOV #27.,R1 ; Count of letters 2$: MOV R0,(R2)+ ; Set up address SOB R1,2$ MOV #25.*26.,R1 ; Number of addresses for second letters MOV #SNDLET,R0 ; Address of second letters 3$: CLR (R0)+ ; Offset 0 SOB R1,3$ INC FSTLET+52. .IF DF RT11 .SETTOP #-2 ; Top address available MOV R0,MEMLIM ; Store memory limit .ENDC .IIF DF R$$11M, MOV MEMLIM,%0 ; Fetch memory top address SUB FREE,R0 ; Amount of free memory SUB FRESPC,R0 ; Allow required free space .IF DF M$$EIS RHI=%4 ; High order result of %4*%5 RLO=%5 ; Lo word MOV FILEN,R4 ; Get system dictionary size in blocks MUL #327.,R4 ; * fraction of words in a block(327/512) ; =letters for storage from dictionary .IFF RHI=%3 ; High order result of %4*%5 RLO=%4 ; Lo word MOV FILEN,R5 ; Get system dictionary size in blocks MOV #327.,R4 ; Fraction of words in a block(327/512) JSR PC,MUL ; R4=letters for storage from dictionary .ENDC CMP R0,RLO ; Too many for available core ? BHI 5$ ; No go do dictionary .IF DF R$$11M ; Not enough default memory. If extend task is available, make enough, ; otherwise, must truncate dictionary space. .IF DF E$$XPR MOV RLO,RHI ; Compute SUB %0,RHI ; w/o destroying %0 or dictionary size MORMEM RHI,31$ ; Try to get some more space. Trap to 31$ on error BR 5$ ; OK, go do full dictionary 31$: ; Failed, trap to here .ENDC ; Not enough space, and can't extend task, must truncate dictionary. .ENDC MOV RLO,R1 ; Save number of letters for storage MOV #34.,R2 ; 2*length of words 4$: TST -(R2) ; Decrement length of words .IF DF M$$EIS MOV R1,R4 ; Get number of letters in dictionary MUL NUMWRD-8.(R2),R4; Fraction of letters in dic of len<=r2/2 ; =actual no of words with len<=r2/2 .IFF MOV R1,R5 ; Get number of letters in dictionary MOV NUMWRD-8.(R2),R4; Fraction of letters in dic of len<=r2/2 JSR PC,MUL ; Actual no of words with len<=r2/2 .ENDC CMP R0,RHI ; Will these fit in memory? BLOS 4$ ; No so try only shorter words ASR R2 ; Maximum length of words we can store MOV R2,LIMLEN ; Store it .IF DF RT11 .PRINT #LIMMSS ; Tell user what we've done MOV LIMLEN,R0 JSR PC,VALR0 ; Print maximum length of words loaded .PRINT #ELMMSS 5$: MOV #10.,FILE ; File number being processed JMP NXTFLE ; Go to basic PSECT .ENDC .IF DF R$$11M MOV %2,%1 ; Load max length of words MOV #LIMMSN,%0 ; and place in message for it MOV PC,%2 ; No zero-suppression JSR PC,$CBDAT ; Convert to ASCII, 2 digits TIMESG #LIMMSS,#LIMMSL ; Print warning message .IIF DF P$$OFF, JSR PC,SETWRN ; Set warning exit status 5$: .ENDC .PAGE .IF DF RT11 .PSECT NXTFLE::.WAIT FILE ; Process file if open BCS NOFIL BIS #DICT!WRDBEG,CODE ; Set dictionary flag JSR PC,ANA ; Load dictionary MOV @#42,SP ; Retores system stack pointer NOFIL: DEC FILE ; Input files except 3 are dictionaries CMP FILE,#3 BNE NXTFLE MOV INROUT,GETCHR ; Set routine to handle input file format BIS #WRDBEG!CHCRLF,CODE ; Set word start and not dictionary BIC #DICT,CODE ; Set word start and not dictionary MOV #MXWORD,LIMLEN ; Allow words of all lengths in JSR PC,ANA ; Analyse text file 1$: .PRINT #NOWRDM MOV NOWRDS,R0 JSR PC,VALR0 ; Print number of words in dictionary .PRINT #FRELET MOV MEMLIM,R0 SUB FSTLET+52.,R0 ; Remaining space JSR PC,VALR0 .PRINT #TERM MOV #511.,R1 2$: CLR R0 JSR PC,PUTOUT ; Flush the output file SOB R1,2$ .CLOSE OFILE ; Close difference file MOV #1,OFILE .WAIT OFILE BCS 3$ JSR PC,PUTDIC ; Output dictionary to file 1 .CLOSE OFILE 3$: MOV (PC),R0 ; Make R0 non zero .EXIT .ENDC .IF DF R$$11M ; Load default dictionaries if required, first making sure that the ; input file exists. DICFIL: MOV SWWRD,CODE ; Get switch word ask, guess and load bits BIC #^C,CODE ; into CODE, where ANA expects them CSI$1 #CSIBLK ; Reset CSI block BCS 4$ ; Shouldn't fail -- worked last time MOVB #CS.INP,@%0 ; Assume there are inputs (note: CS.TYPR=0) BITB #CS.EQU,C.STAT(%0) ; But if no '=' sign BNE 2$ ; read from the (only) output list INCB @%0 ; So switch to outputs (CS.TYPR=0 & CS.OUT=CS.INP+1) 2$: CSI$2 ,,#SWTAB ; Fetch and skip 1st input BITB #CS.DVF!CS.DIF!CS.NMF!CS.MOR,C.STAT(%0) BNE DODIC ; OK if an I/P file or following dictionaries 4$: JMP CMDERR ; Error if no inputs or dictionaries ; Load default dictionaries if required/necessary. DODIC: BIS #DICT!WRDBEG!CHCRLF,CODE ; Set dictionary flags MOV #NULL,GETCHR ; Read all text for dictionaries BIT KEEPD,SWWRD ; Keep old dictionaries? BNE NODIC ; Yes, don't load defaults TSTB SWWRD ; Don't load defaults? (DDBIT is bit 7) BMI NODIC ; Yes, if bit SET, just get user specified dics TST GOTDD ; Def dics got last time, and unchanged still? BNE NODIC ; Yes, just look for user's INC GOTDD ; No, say we are fetching dics MOV #DICFDB,%0 ; Address system dictionary file FDB TST F.BDB(%0) ; See if it was opened successfully BEQ 10$ ; No, can't read it JSR PC,ANA ; Load dictionary MOV SPSAVE,SP ; Restore stack pointer CLOSE$ #DICFDB ; Close file 10$: JSR PC,USRDIC ; Open user dictionary (if it exists) BCS NODIC ; Don't read if it doesn't RDDIC: JSR PC,ANA ; It does, process MOV SPSAVE,SP ; Reset SP again CLOSE$ #DICFDB ; Finished with dictionary ; Input files after the first are also dictionaries NODIC: FDOP$R #DICFDB,,#CSIBLK+C.DSDS,#OUTDEF,#FO.RD ; Reset file open mode BITB #CS.MOR,CSIBLK+C.STAT ; Any more inputs? BEQ DUNDIC ; No, all dictionaries done CSI$2 #CSIBLK ; Yes, parse for next dictionary CLR GOTDD ; Cannot assume default dictionaries unchanged MOV #DICFDB,%0 ; Open file JSR PC,OPEN BCC RDDIC ; Read dictionary if open OK OPNERJ: JMP OPNERR ; Failed, print error message & give up ; Done dictionary. Now open list file, and do input. DUNDIC: BIC #DICT,CODE ; Clear dictionary load flag MOV #KDBIT,KEEPD ; Recognise /KD bit on subsequent runs CLR QUERYS ; Clear queried words counter CLR RECORD ; Clear input file record number CLR LINPOS ; Clear list file line pointer CLR TOTWRD ; Clear total words counter CSI$1 #CSIBLK ; Reset CSI control block MOVB #CS.INP,@%0 ; Look for first input file BITB #CS.EQU,CSIBLK+C.STAT ; Noting that if there is no = sign BNE 1$ INCB @%0 ; it's actually on the (only) output side 1$: CSI$2 ,,#SWTAB ; Fetch 1st input BITB #CS.DVF!CS.DIF!CS.NMF,C.STAT(%0) ; Do we have a file? BEQ 2$ ; No, just finish up output MOV #INFDB,%0 ; Address input FDB JSR PC,OPEN ; Open it BCS OPNERJ ; Trap open error MOV INFDB+F.FNB+N.FTYP,DEFTYP ; Save filetype in case switches latched ; We now have a filetype. If there were no switches to say otherwise, use it to ; decide test mode (c.f. above). TST LANG ; Any language switches given? BNE 2$ ; Yes, keep them MOV #LNGTAB,%1 ; No, address language table MOV #NLANG,%2 ; and no of them 12$: CMP F.FNB+N.FTYP(%0),(%1)+ ; Compare filetype with table BEQ 13$ ; Exit loop if found CMP (%1)+,(%1)+ ; Else skip subroutine and comment chars SOB %2,12$ ; and keep looking MOV #LNGTAB+2,%1 ; Not found, default to straight text 13$: MOV (%1)+,INROUT ; Found (or end). Load processor routine BIT #CCBIT,SWWRD ; COMMENT characters specially defined? BNE 2$ ; Yes, keep user's MOV (%1)+,COMMENT ; No, use defaults ; Open the list file (if any), default to TI: if not, leave CSI block set up ; for output dictionary filename fetch. 2$: MOV #TI0DSD,%2 ; Load dataset descriptor for default output to TI: BITB #CS.EQU,CSIBLK+C.STAT ; If there isn't a '=' BEQ 3$ ; Default listing to TI: MOV #CSIBLK,%0 ; Else point back at CSI control block INCB @%0 ; Switch from inputs to outputs CSI$2 ; Parse for list file BITB #CS.NMF!CS.DIF!CS.DVF,CSIBLK+C.STAT ; Is there a file name? BEQ 3$ ; No, keep default TI: MOV #^RLST,OUTDEF+N.FTYP ; Yes, make default file SPELL.LST MOV #CSIBLK+C.DSDS,%2 ; Load dataset descriptor pointer 3$: FDOP$R #OUTFDB,,,,#FO.WRT ; Set file open for write JSR PC,OPDSD ; Open file with appropriate dataset descriptor MOV #^RWRD,OUTDEF+N.FTYP ; Change name back to SPELL.WRD BCS OPNERJ ; Trap open error ; Set flag byte LSISTI <> 0 if list file is TI:, default or explicit. CLRB LSISTI ; Assume not CMP OUTFDB+F.FNB+N.DVNM,TIDEV ; But is list device a terminal? BNE 4$ ; No, leave flag clear CMP OUTFDB+F.FNB+N.UNIT,TIUNIT ; Yes, same unit number as TI:? BNE 4$ ; No, not TI: COMB LSISTI ; Yes, it is 4$: JSR PC,OUTINI ; Set up output buffers TST INFDB+F.BDB ; Is there an input file? BEQ 8$ ; No, just output dictionary statistics + new dict MOV INROUT,GETCHR ; Set routine to handle input file format BIS #WRDBEG!CHCRLF,CODE ; Set word start MOV #MXWORD,LIMLEN ; Allow words of all lengths in MOVB #'N,ANSWER ; Initial default reply to query is No MOV #INFDB,%0 ; Address input FDB JSR PC,ANA ; Analyse text file MOV SPSAVE,SP ; Restore stack pointer CLOSE$ #INFDB ; Close input file ; Finish up output by printing word count, error count and dictionary size ; in output file and on TI: (unless same thing). 5$: NUMBER TOTWRD,#NTOTLM ; Put total no of words read in message MOV QUERYS,%1 ; Get number of queried words BEQ 7$ ; Just output if 0 .IIF DF P$$OFF, JSR PC,SETWRN ; Set warning exit status BIT #LOBIT,SWWRD ; Were errors loaded into dictionary? BEQ 7$ ; No, defaults not corrupted CLR GOTDD ; Yes, force reload of default dics 7$: NUMBER ,#QUERYN ; Convert to 5-digits decimal 8$: NUMBER NOWRDS,#NWORDS ; Put in number of words now in dictionary MOV MEMMAX,%1 ; Compute remaining space SUB FSTLET+52.,%1 ; in bytes from top of fully-extended task NUMBER ,#NMORE ; Put no of characters in too ; End file with statistics. JSR PC,CRLF ; Put in a blank line TST RECORD ; Any input records read? BEQ 9$ ; If 0, don't report words/errors counts JSR PC,CRLF ; Blank line again MOV #QUERYN,%0 ; Print total words and number of queried words JSR PC,OUTPUT 9$: JSR PC,CRLF ; Another blank line MOV #NWORDS,%0 ; then dictionary size JSR PC,OUTPUT ; (Sets %0->OUTFDB) .IF DF R$$11M ; Close difference list file, spooling if required. BIT #SPBIT,SWWRD ; Spool required? BNE 10$ ; No if SET, just close JSR PC,.PRINT ; Yes, spool BCC 20$ ; OK, continue 10$: CLOSE$ ; Spool failed, or not reqd. Just close .ENDC 20$: TSTB LSISTI ; Is list device TI:? BNE 30$ ; Yes, don't print twice TST RECORD ; Unless no input file BEQ 27$ TIMESG #QUERYM,#QUERYL ; Print no of queries 27$: TIMESG #NOWRDM,#NOWRDL ; and dictionary space used/left ; Output accumulated dictionary if file specified. 30$: BITB #CS.EQU,CSIBLK+C.STAT ; Any output files at all? BEQ NXTCMJ ; Not if no '=', can't be an O/P dictionary spec BITB #CS.MOR,CSIBLK+C.STAT ; Dictionary output required? BEQ NXTCMJ ; No go straight to next command CSI$2 #CSIBLK ; Yes, fetch filename MOV #OUTFDB,%0 ; Open file JSR PC,OPEN BCC 40$ ; Continue if OK 35$: JMP OPNERR ; or trap open error 40$: JSR PC,OUTINI ; Set up output buffers JSR PC,PUTDIC ; Output dictionary CLOSE$ #OUTFDB ; Close NXTCMJ: JMP NXTCMD ; Repeat or exit .ENDC .PAGE ANA: MOV (SP)+,(PC)+ ; Store return add so it can be jumped to RETAD: .WORD 0 ; Stores main program return address .IF DF R$$11M MOV %0,IFLFDB ; Save input file FDB address TIMESG #TICRLF,#2,#0 ; Make sure messages start on a new line .ENDC .IIF DF R$$T11, .TTYOUT #CR ; Make sure messages start at LH column CLR ESW ; Clear e-o-f flag before 1st read JSR PC,INITIL ; Initialise file BIT #DICT,CODE ; Starting a dictionary load? BEQ LOP2A ; No, branch TIMESG #LOADIN,#LOADL,ASLAST ; Print "Loading dictionary." .IF DF R$$11M MOV #DOT,TIQIOW+Q.IOPL ; Series of dots will follow MOV #1,TIQIOW+Q.IOPL+2 ; on same line .ENDC LOP2A: MOV CODE,R3 ; Get code back LOP2B: MOV #WRDBUF,R4 ; Reset address of buffer for words CLR R1 ; Reset count of letters in word LOP2C: BIC #TNLOAD!TNGESS,R3 ; Clear temporary inhibitions LOP2: JSR PC,@GETCHR ; Get char and find out what it is CMPB #'-,R0 ; Was character hypen? BNE 1$ JSR PC,HYPHEN ; Special code for hyphen 1$: BIT #1,R5 ; Was character apostrophe or punctuation? BEQ 2$ JSR PC,PUNCTU ; Special code for punctuation 2$: BIT #2,R5 BNE LOP2 ; Ignore ^ and \ BIT #WRDBEG,R3 BNE PASS4 ; Jump if in middle of word PASS12: TSTB R5 BGE LOP2 ; Jump if new char not word start BIS #WRDBEG,R3 ; Set to indicate new word BR PASS5 ; Go and see if word complete PASS4: BIT #100,R5 BNE PASS5 ; Jump if new char not word end BIT #4,R5 ; Is it a character? BNE PASS9 BIC #WRDBEG,R3 ; Non-alphabetic char in word, reject CLR R1 MOV #WRDBUF,R4 BR PASS12 PASS9: CMP #MXWORD,R1 ; Test for max length word BEQ LOP2 PASS6: INC R1 ; Store next letter of word MOVB R0,(R4)+ ; Move next letter into buffer BR LOP2 PASS5: BIT #100,R5 ; Test for end of word BEQ LOP2 TSTB R5 ; Test for word start BLT PASS7 BIC #WRDBEG,R3 ; Clear word flag if not start of new ; Now have a word of %1 letters in area WRDBUF. First check for formats ; which should be ignored. PASS7: TST %1 ; Zero-length word (two adjacent separators)? BEQ LOP2C ; Yes, go back INC TOTWRD ; Found a word, count it CMP R1,LIMLEN ; Is word longer than can load? BGE LOP2B ; Yes so ignore it CMP R1,MINLEN ; Is word shorter than user requires? BLE LOP2B ; Yes so ignore it ; If the IU switch is on, and this is not a dictionary, ignore words ; wholly in upper case. Since we only have letters, just test bit 5. BIT #DICT,%3 ; Is this a dictionary? BNE 20$ ; Yes, they can be in upper case TST AUXSWD ; Does user want to ignore UC words? (bit 15) BPL 20$ ; No, go check whatever happens MOV #WRDBUF,%2 ; Yes, address start of stored word MOV %1,%5 ; Load length counter 10$: BITB #40,(%2)+ ; Is this an LC letter? BNE 20$ ; Yes if bit set, go lookup word SOB %5,10$ ; Test whole word BR LOP2B ; Ignore if all UC 20$: MOV R3,CODE ; Save R3 as code MOV R1,LETCNT ; Store length of word SUB #2,R1 ; Only deal with words >=2 letters BNE 1$ ; Jump for 3 and more letters INC LETCNT INC R1 ; Force 2 letters to be 2 + space MOVB #SPACE,(R4)+ ; Insert space as second 1$: MOV R1,CURLEN ; Store length of word-2 MOV #WRDBUF,R0 ; Constructed word location MOV #CMPBUF,R3 ; For word form for searching MOV R3,R2 MOVB (R0)+,R5 ; Get first letter BISB #40,R5 ; and make lower case MOVB (R0)+,R4 ; Same for second letter BISB #40,R4 2$: MOVB (R0)+,(R2) ; Now transfer word minus first two letters BISB #40,(R2)+ ; And make lower case SOB R1,2$ ; Length of word -2 .IIF DF DEBUG CLRB (R2) BISB #200,-(R2) ; Set parity to indicate last letter MOVB #200,(R0) ; and clear so word can be .PRINTed .IIF DF DEBUG .PRINT #WRDBUF ; Show new word SUB #'a,R5 ; DeASCII first letter MOV R5,FLETST ; Store it ASL R5 ; Double for word offset MOV FSTLET(R5),R0 ; Get address MOV R0,R1 ; Get address for end of search SUB #'a+1,R4 ; DeASCII second letter MOV R4,SLETST ; Store it ASL R4 ; Double for word offset BCC 3$ ; Jump if a ADD SLETAD(R5),R4 BR 4$ 3$: ADD SLETAD(R5),R4 ; Add in offset in table ADD SNDLET(R4),R0 ; Add dictionary offset to basic address 4$: ADD SNDLET+2(R4),R1 CMP #'z-'a-1,SLETST ; Was second letter z? BNE 5$ ; Jump if not end of second letter table MOV FSTLET+2(R5),R1 ; End of search area for this letter CMP %5,#<'z-'a>*2 ; unless first was also 'z' BNE 5$ ; When FSTLET+2(%5)=FSTLET+52., we must DEC %1 ; subtract the 1 added at start of program 5$: MOV R0,SSEARC ; Store address of start of search area MOV R1,ESEARC ; Store address of end of search area CMP R0,R1 ; Have we reached end of search area? BHIS NOTFND ; Yes so word not found 6$: MOV R3,R2 ; Address of word to be searched for 7$: CMPB (R0),(R2)+ ; Does next letter correspond? BNE 8$ ; No so jump TSTB (R0)+ ; Is this end of word? BGE 7$ ; No so loop JMP LOP2A ; Yes so word found 8$: TSTB (R0)+ ; So search for end of word BGE 8$ CMP R0,R1 ; Have we reached end of search area? BLO 6$ ; No so continue, else word not found NOTFND: BEQ 1$ ; Addresses should be equal .IF DF RT11 .PRINT #NEQ .EXIT .ENDC .IF DF R$$11M TIMESG #NEQ,#NEQL ; Internal consistency check failed if not .IIF DF P$$OFF, MOV #EX$SEV,%0 ; Severe error JMP $EXST ; Abort program run .ENDC 1$: INC QUERYS ; Count a queried word JSR PC,SPLERR ; Routine which prints spelling errors BIT #DICT!NLOAD,CODE ; Dictionary or word insertion reqd? BEQ 7$ ; No so don't put it in dictionary BIT #TNLOAD,CODE BNE 7$ MOV FSTLET+52.,R1 ; Current end of dictionary MOV R1,R2 ; Now make space in buffer for word ADD CURLEN,R2 ; Address of new end of buffer BCS 13$ ; Out of memory if it overflows 11$: CMP R2,MEMLIM ; Does this exceed core? BLO 2$ ; No so jump .IIF DF RT11,13$: .PRINT #MEMOVF ; Yes so message .IF DF R$$11M .IF DF E$$XPR ADD #512.,MEMLIM ; Yes, allocate some more EXTK$S #512./64. BCC 11$ ; Go try again if OK .ENDC SUB #512.,MEMLIM ; Reset memory pointer 13$: TIMESG #WARMSG,#WARMGL,#STMSG ; Failed, print error message TIMESG #MEMOVF,#MEMOVL,#ENDMSG .IIF DF P$$OFF, JSR PC,SETWRN ; Set warning exit status .ENDC BIS #NLOAD,CODE ; Don't try to store any more new words BIT #DICT,CODE ; if this is a source file, BEQ 7$ ; just guess from now on JMP @RETAD ; Give up loading if it's a dictionary ; Make space in dictionary by shifting up from where %1 points (old end) ; to where %2 points (new). If both are even, move words for speed, if ; not, must move bytes. %0 addresses place to put new word. 2$: SUB %1,%0 ; Compute no of bytes to shift BEQ 3$ ; Trap (error) case of none NEG %0 ; Get sign of count right ; If both end addresses are even, we can shift by words MOV %1,-(SP) ; Push old pointer BIS %2,@SP ; OR with new ROR (SP)+ ; Is bit 0 clear in both? BCC 21$ ; Yes, go shift fast ; If both are odd, a single byte shift will make them both even. MOVB -(%1),-(%2) ; Try a single-byte shift DEC %0 ; Count it BEQ 3$ ; Done if that was all MOV %1,-(SP) ; Repeat test BIS %2,@SP ROR (SP)+ ; For either still odd? BCS 27$ ; Yes, must move bytes, go see if 1 was enough ; *** WARNING: ENSURE THAT CARRY IS CLEAR AT THIS POINT *** 21$: ROR %0 ; No, halve (unsigned) count for no of words BEQ 25$ ; 0 means just 1 more byte left ROL -(SP) ; Save odd byte flag (if any) 23$: MOV -(%1),-(%2) ; Shift byte pairs SOB %0,23$ ; until done ROR (SP)+ ; Do we have an odd byte left? BCC 3$ ; No, all done 25$: INC %0 ; Yes, 1 last byte to shift 27$: MOVB -(R1),-(R2) ; Shift dictionary up a byte at a time SOB R0,27$ ; until done 3$: MOV CURLEN,%0 ; Now shift new word into dictionary -- get length 31$: MOVB (R3)+,(R1)+ SOB %0,31$ INC NOWRDS ; Count of words in dictionary ; If this is a (probably slow) dictionary load, output a '.' every 256 words ; to show something is happening. BIT #DICT,CODE ; Doing a dictionary load? BEQ 35$ ; No, branch BIT #128.-1,NOWRDS ; Yes, done a multiple of 128 words? BNE 35$ ; No, not time to show yet .IIF DF R$$11M, DIR$ #TIQIOW ; Yes, output '.' to show something's happening .IIF DF R$$T11, .TTYOUT <#'.> ; Yes, output '.' to show something's happening 35$: MOV CURLEN,R0 ADD #SNDLET+2,R4 4$: CMP #'z-'a-1,SLETST ; Are we at end of second letter table? BEQ 5$ ADD R0,(R4)+ INC SLETST BR 4$ 5$: ADD #FSTLET+2,R5 ; Now update first letter addresses 6$: ADD R0,(R5)+ INC FLETST CMP #26.,FLETST BGT 6$ 7$: ; This segment makes a guess of what the word should be. GUESS: BIT #TNGESS!DICT!NGUESS,CODE ; Is a guess required? BNE 8$ ; Yes so don't guess CMP #2,CURLEN ; Only guess for the longer words BGE 8$ ; Too short so jump MOV SSEARC,R5 ; Address of start of search area CMP R5,ESEARC ; Are there any words to compare? BHIS 8$ ; No so jump MOV R4,R1 ; Default address of closest match CLR CORRES ; Maximum correspondence so far 1$: CLR R2 ; Current correspondence length CLR R0 ; Length of dictionary word count MOV R5,R4 ; Address of current comparison word MOV #CMPBUF,R3 ; Address of base word 2$: INC R2 ; Up correspondence count INC R0 ; Up length of word count CMPB (R3)+,(R5)+ ; Do letters correspond? BEQ 2$ ; Yes so jump DEC R5 ; Look at last letter compared 3$: INC R0 ; Up length of word count TSTB (R5)+ ; Look for end of word BGE 3$ DEC R0 ; Adjust length of word SUB CURLEN,R0 ; Subtract of length of matching word BPL 4$ NEG R0 ; Make positive 4$: SUB R0,R2 ; Now weight corres count with lengths MOV R5,R0 ; Now match words backwards MOV #CMPBUF,R3 ; Construct end of word+1 ADD CURLEN,R3 ; Length of word -2 5$: INC R2 ; Up correspondence count CMPB -(R3),-(R0) ; Do they correspond? BEQ 5$ ; Yes so jump CMP R2,CORRES ; Greater than previous best match? BLE 6$ ; No so jump MOV R2,CORRES ; Yes so this is new best MOV R4,R1 ; Address of best 6$: CMP R5,ESEARC ; End of search area BLO 1$ ; No so loop CMP #3,CORRES ; Must have >3 for reasonable match BGE 8$ ; Jump if not good enough match MOV #CMPBUF,R5 MOVB #'(,(R5)+ MOVB WRDBUF,(R5) BISB #40,(R5)+ MOVB WRDBUF+1,(R5) BISB #40,(R5)+ 7$: MOVB (R1),(R5) BICB #200,(R5)+ ; Clear off parity TSTB (R1)+ ; End of word? BGE 7$ ; No so loop MOVB #'),(R5)+ MOVB #200,(R5) MOV #CMPBUF,R0 SUB R0,R5 ; Length of string in R5 ADD R5,LINPOS ; Update line position JSR PC,OUTPUT 8$: JMP LOP2A ; Get another word .PAGE ; This routine is called whenever a word is to be inserted in a dictionary. SPLERR: BIT #DICT,CODE ; Is this a dictionary? BNE 6$ ; Yes, so don't print or ask MOV R0,-(SP) ; No, save a working register BIT #ASK,CODE ; Should we ask about this word? BEQ 3$ ; No, just list ; Print message Load "word" [Yes/No/Go/Quit]? and get reply: ; Y to put word in dictionary (and not list) ; N to leave word out of dictionary, and add to queries list ; Q to leave this and all subsquent words out, list, & stop asking. ; G to load word and all subsequent ones without asking. 1$: TIMESG #LOADQ,#LOADQL,#STMSG ; Print Load " TIMESG #WRDBUF,LETCNT,#0 ; Append word itself .IF DF R$$11M .IIF NDF T$$RPR, TIMESG #YNGQ,#YNGQL,ASLAST ; Complete message " [Yes/No..." DIR$ #ASKOP ; Get user's reply MOVB ANSWER,%0 ; To %0 (default is as last) .ENDC .IF DF R$$T11 .PRINT #YNGQ ; Complete message with " [Yes/No... .TTYIN ; Get reply to %0 MOV %0,-(SP) ; Save it .TTYIN ; Skip CR supplied by terminal driver MOV (SP)+,%0 ; Get 1st reply char back .ENDC BIC #40,%0 ; Make sure reply is upper-case BIC #NLOAD,CODE ; Assume don't load this word CMPB %0,#'N ; If reply is No BEQ 2$ CMPB %0,#'Q ; or Quit BEQ 12$ ; in which case go clear ask bit too BIS #NLOAD,CODE ; Y or G require load flag set CMPB %0,#'Y ; Is it Y? BEQ 2$ ; Yes, go print if required CMPB %0,#'G ; Is it G? BNE 1$ ; Repeat question if anything else 12$: BIC #ASK,CODE ; Don't ask any more if G or Q 2$: TSTB LSISTI ; Listing on TI:? BNE 55$ ; Yes, don't print word again 3$: BIT #WIBIT,AUXSWD ; Do we want only one per line? BNE 4$ ; Yes, must do new line ; Set output to column 0, 24 or 48, if not past all three. .IIF DF AUTOHT,; Column numbers must be multiples of 8. TST LINPOS ; No, at beginning of line? BEQ 5$ ; Yes, continue JSR %5,SETCOL ; Try to tab to col .WORD 24. ; 24 BEQ 5$ ; Continue if succeeded JSR %5,SETCOL ; If not, try col .WORD 48. ; 48 BEQ 5$ ; OK if success 4$: JSR PC,CRLF ; Failed, need a new line 5$: ; If printing every occurrence of an error, prefix it with a record or ; sequence number, in square brackets. BIT #EVBIT,CODE ; Print all? BNE 52$ ; No if bit clear, don't do line number MOV %1,-(SP) ; Save registers used MOV %2,-(SP) MOV RECORD,%1 ; Load record counter .IF DF R$$11M CMPB INFDB+F.RTYP,#R.SEQ ; But are records sequenced? BNE 51$ ; No, keep the records read counter MOV INFDB+F.SEQN,%1 ; Yes, use sequence number instead .ENDC 51$: MOV #RECNO+1,%0 ; Address line number string SUB %0,LINPOS ; Start output line position pointer update CLR %2 ; %2=0 for leading 0 suppression JSR PC,$CBDMG ; Convert to ASCII MOVB #'],(%0)+ ; Terminate with ']' MOVB #SPACE,(%0)+ ; and space MOVB #200,(%0)+ ; and 200 to suppress CR/LF ADD %0,LINPOS ; Complete position pointer update MOV #RECNO,%0 ; Address line number string JSR PC,OUTPUT ; Output string MOV (SP)+,%2 ; Restore registers MOV (SP)+,%1 52$: ADD LETCNT,LINPOS ; Add in length of word MOV #WRDBUF,R0 ; Print word in error JSR PC,OUTPUT 55$: MOV (SP)+,R0 6$: RTS PC ; Set character position to column number in word following JSR %5 call. ; Call as: JSR %5,SETCOL ; .WORD column no .IF DF AUTOHT ; N.B. Column numbers must be multiples of 8. NXTCOL: MOV #HT,%0 ; Load tab .IFF NXTCOL: MOV #SPACE,%0 ; Load space .IFTF JSR PC,PUTOUT ; Output it .IFT ADD #8.,LINPOS ; Update column count BIC #7,LINPOS ; to next multiple of 8 cols .IFF INC LINPOS ; Update column count .ENDC ; AUTOHT TST -(%5) ; Reset pointer to reqd col value SETCOL: CMP (%5)+,LINPOS ; Reached (or already past) required position? BGT NXTCOL ; No, space again RTS %5 ; Yes, return, z = there, nz = past ; This routine passes a character either to terminal or file if specified. OUTPUT: MOV R1,-(SP) MOV R0,R1 .IF DF RT11 .WAIT #0 ; Is there a file? BCC 2$ .PRINT R1 1$: MOV (SP)+,R1 RTS PC .ENDC 2$: MOVB (R1)+,R0 BLE 3$ JSR PC,PUTOUT BR 2$ 3$: BNE 1$ ; 200 so end JSR PC,CRLF ; Output new line .IIF DF RT11, BR 1$ .IF DF R$$11M 1$: MOV (SP)+,%1 ; Restore %1 RTS PC ; and exit .ENDC ; This routine puts char in R0 to file. PUTCHR: CMPB #'a,R0 ; Is this a letter? BGT PUTOUT ; No so jump BICB AUXSWD,R0 ; Yes so change to upper case if req PUTOUT: MOVB R0,@OFLPTR INC OFLPTR DEC OFLCNT BNE PUTEX .IF DF RT11 .WRITW #EMTBUF,OFILE,#OUTBUF,#256.,OFLBLK BCS PUTERR INC OFLBLK MOV #OUTBUF,OFLPTR MOV #512.,OFLCNT .ENDC .IF DF R$$11M ; Output current line. CRLF: SUB OUTFDB+F.NRBD+2,OFLPTR ; Compute length PUT$S #OUTFDB,,OFLPTR ; Output buffer (PUT$S to match GET$S) BCS PUTERR ; Trap error OUTINI: MOV OUTFDB+F.NRBD+2,OFLPTR ; Load buffer pointer MOV OUTFDB+F.NRBD,OFLCNT ; and max bytes CLR LINPOS ; Reset line pointer CLR LNFLG ; and done line flag .ENDC PUTEX: RTS PC ; Return .IF DF RT11 PUTERR: .PRINT #WERMSG .EXIT .ENDC .IIF DF R$$11M,PUTERR: ERROR #WERMSG,#WERMGL,FILERR ; Take error exit .PAGE ; This routine dehyphenates words, entered when hyphen detected. HYPHEN: JSR PC,PEEP ; Peep at next character CMPB #CR,R0 ; Is it new line? BNE 1$ ; No so word not hyphenated 2$: JSR PC,@GETCHR ; Yes so search for next letter BIT #10,R5 ; Skip CR, LF, FF BNE 2$ RTS PC 1$: MOV #'-,R0 ; Regenerate last character MOVB TABLE(R0),R5 RTS PC ; This routine deals with apostrophied words, whether word in apostrophes ; or apostrophied. ; Also deals with punctuation marks making sure they are followed by ; a space, unless ignoring them (/IP switch on). PUNCTU: CMP #1,R1 ; Must have >2 letters in word already BGE 1$ ; No so can't be apostrophied word MOV R0,-(SP) ; Save character JSR PC,PEEP ; Peep at next character BIT #4,R5 ; Is it a character? BEQ 3$ ; No, must be a terminator CMPB #'',@SP ; Yes, except for apostrophe, BEQ 6$ BIT #IPBIT,AUXSWD ; see if we should report embedded punctuation BNE 3$ ; Treat as a word ending if not 6$: BIS #TNGESS,R3 ; Disable guess ; BIS #TNLOAD!TNGESS,R3 ; Disable guess and don't insert CMPB #'',(SP) ; Was last character an apostrophe? BNE 5$ ; No so jump BIC #TNLOAD,R3 ; Allow insertion but not guessing for ' CMPB #'s,R0 BNE 2$ 3$: MOV #300,R5 ; Make hyphen word end only BR 4$ 2$: CMPB #'S,R0 BEQ 3$ 5$: MOV #4,R5 ; Pretend it's a character 4$: MOV (SP)+,R0 1$: RTS PC ; This routine puts out the dictionary. PUTDIC: CLR FMFLG ; Pretend we just had a form feed DEC FSTLET+52. ; Take off 1 put on at start of prog MOVB #'a,FLETST MOV #FSTLET,R4 MOV #SNDLET+4,R3 MOV (R4),R5 ; First dictionary entry 1$: MOV #'a,SLETST ; Second letter of words MOV R5,R2 SUB #4,R3 ADD (R3)+,R2 2$: CMP R2,R5 ; Is there anything for this 2 let comb? BEQ 4$ ; Yes so jump 3$: JSR PC,ONXWRD ; Read word out of dictionary INC LNFLG ; Indicate something output INC FMFLG ; Past form feed CMP R2,R5 ; Are we at end of this 2 let comb? BNE 3$ ; No so continue 4$: TST LNFLG ; Do we throw a line? BEQ 5$ ; Not if just done one JSR PC,CRLF 5$: INCB SLETST ; Change second letter MOV (R4),R2 ; Work out new limit ADD (R3)+,R2 CMPB #'z,SLETST ; Have we done all these 2nd letters? BGT 2$ ; No so continue BLT 6$ ; Yes so jump TST (R4)+ ; Last one (Z) MOV (R4),R2 ; So recalc new limit BR 2$ 6$: INCB FLETST ; Move onto next first letter TST FMFLG ; Unless just done so BEQ 7$ MOV #FORM,R0 ; Throw a page JSR PC,PUTCHR CLR FMFLG ; Remembering it 7$: CMPB #'z,FLETST ; Done all dictionary? BGE 1$ ; No so jump .IF DF RT11 JSR PC,CRLF ; Yes, finish with CR/LF MOV #511.,R1 ; and rest of buffer clear 7$: CLR R0 JSR PC,PUTCHR SOB R1,7$ RTS PC .ENDC .IIF DF R$$11M, JMP CRLF ; Yes, flush last line and exit ONXWRD: MOV R5,-(SP) ; Save address of word MOV #3,R1 1$: INC R1 ; Calc length of next word TSTB (R5)+ BPL 1$ BICB #200,-(R5) ; Clear off parity ADD R1,LINPOS CMP LINLEN,LINPOS ; Reached end of line? BGE 2$ ; Will go beyond end of line JSR PC,CRLF MOV R1,LINPOS ; Reset length of word 2$: MOVB FLETST,R0 ; Get first letter JSR PC,PUTCHR MOVB SLETST,R0 JSR PC,PUTCHR SUB #3,R1 ; Decrement word length by 2 MOV (SP)+,R5 ; Restore address of word 3$: MOVB (R5)+,R0 JSR PC,PUTCHR DEC R1 BGT 3$ MOVB #SPACE,R0 JMP PUTCHR ; Output space and return .IF DF RT11 CRLF: CLR LINPOS ; Clear line pointer CLR LNFLG ; and done line flag MOVB #CR,R0 JSR PC,PUTCHR MOVB #LF,R0 JMP PUTCHR ; Output line feed and return .ENDC .PAGE .IF DF RT11 ; This routine converts to ASCII a number contained in R0 and prints it. ; VALR0 gives signed number, NUMBR1 gives unsigned. ; R0 and R1 are used. VALR0: MOV R0,-(SP) 1$: CLR R0 2$: INC R0 SUB (PC)+,(SP) 3$: .WORD 10. BHIS 2$ ADD (PC)+,(SP) 4$: .WORD 72 DEC R0 BEQ 5$ JSR PC,VALR0 5$: .TTYOUT (SP)+ RTS PC .ENDC .IF DF R$$11M ; Puts 5-digit number supplied in %1 into text area addressed by %0, as ; 5 decimal digits, unsigned, right-justified, and blank-filled. %0 is ; updated, %1 and %2 are destroyed. NUMBR1: MOV #^B10111000001010,%2 ; Load conversion flag bits JMP $CBTA ; output 5 decimal digits, and return .IF DF P$$OFF ; Change exit status to warning unless it is already that or more serious. SETWRN: DEC EXSTAT ; Still flagging success? BEQ 5$ ; If so, EX$SUC=1 changes to EX$WAR=0 INC EXSTAT ; Restore any other (more serious) error code 5$: RTS PC ; Return .ENDC .ENDC ; Gets next character from input file and test it for CR/LF/FF. NULL: JMP @INTCPT ; Goes to RESTOR or INCHAR ; This routine gets next character from input file but leaves it still there. PEEP: MOV #INCHAR,INTCPT ; Make sure get next char JSR PC,@GETCHR ; Get next character MOV R0,SAVECH ; Save character for reuse later MOV #RESTOR,INTCPT ; Switch input routine so savech is used RTS PC ; If last character was 'peeped ' at this gets it properly RESTOR: MOV #INCHAR,INTCPT ; Restore input routine MOV SAVECH,R0 ; Get character peeped at BR TSTCR ; Test for CR/LF/FF ; This routine gets next input character from input file and puts it in R0 ; R5 contains character code. .IIF DF R$$11M,NEWLIN: JSR PC,INITIL ; Back here for a fresh line INCHAR: TST CNT ; Any more in buffer? .IF DF RT11 BNE 5$ INC BLK ; Increment block count .WAIT FILE BCC 1$ ; Need some more JSR PC,ERRHND ; Look for trouble 1$: MOV #BUFFER,R5 ; Address of addresses of 2 buffers .READ #EMTBUF,FILE,(R5),#256.,BLK BCC 4$ ; Need some more JSR PC,ERRHND ; Look for trouble 4$: MOV (R5)+,-(SP) ; Swap buffer addresses over MOV (R5),-(R5) MOV (R5)+,BUFAD ; Set up next buffer address MOV (SP)+,(R5) MOV #512.,CNT ; And byte count .ENDC .IF DF R$$11M BGT 5$ ; Yes if >0 BMI NEWLIN ; Fetch a new line if <0 MOV IFLFDB,%0 ; =0, end of line. Should we return CR? BITB #FD.CR!FD.PRN,F.RATT(%0) ; Yes, if FD.CR or COBOL carriage-control BNE 4$ BITB #FD.FTN,F.RATT(%0) ; Unless FORTRAN carriage-control BEQ NEWLIN ; assume embedded, so don't TST F.NRBD(%0) ; FORTRAN, did we have a blank line? BEQ 4$ ; Yes, return CR CMPB @F.NRBD+2(%0),#'$ ; No, was last line "prompting" carr-ctrl? BEQ NEWLIN ; Yes, don't output a CR 4$: MOV #CR,%0 ; Flag end of line where appropriate BR DECCNT ; Process, setting CNT<0 for next time .ENDC 5$: MOVB @BUFAD,R0 ; Get next char from input buffer INC BUFAD ; Point to next input char DECCNT: DEC CNT ; Update count of chars left in buffer TSTCR: BIC #177600,R0 ; Clear parity MOVB TABLE(R0),R5 ; Look character up in table BIC #CHCRLF,R3 ; Is it CR, LF OR FF? BIT #10,R5 ; Jump if new char not CR/LF BEQ 1$ BIS #CHCRLF,R3 ; Set CR/LF/FF occurred .IF DF RT11 CMPB %0,#CR ; Is it actually a CR? BNE 1$ ; No, just return INC RECORD ; Yes, add 1 to line number .ENDC 1$: RTS PC .IF DF R$$11M INITIL: GET$S IFLFDB ; Get a line of input (use GET$S because GCML does) BCS ERRHND ; Trap error or e-o-f INC RECORD ; Count record read MOV F.NRBD+2(%0),BUFAD ; OK, get buffer address MOV F.NRBD(%0),CNT ; and count BEQ 10$ ; Always return if line blank BITB #FD.FTN,F.RATT(%0) ; Not blank, do we have FORTRAN carr-ctrl? BEQ 10$ ; No, return whole line CMPB @BUFAD,#1 ; Yes, wanting a form feed? BNE 5$ ; No, skip any other carriage-control MOVB #FF,@BUFAD ; Yes, change to a real FF BR 10$ 5$: INC BUFAD ; Skip any other carriage-control char DEC CNT 10$: RTS PC ; Return ERRHND: CMPB F.ERR(%0),#IE.EOF ; Just end-of-file? BNE INPERR ; No, something more serious TST ESW ; Yes, did we have one last time? BNE 10$ ; Exit now if so INC ESW ; No, set flag for next time CLR CNT ; Zero count BISB #FD.CR,F.RATT(%0) ; and set bit to force an end of line RTS PC ; and return 10$: JMP @RETAD ; End-of-file, exit ANA now INPERR: ERROR #INPERM,#INPERL,FILERR ; Take error exit .ENDC .IF DF RT11 ERRHND: TST ESW BEQ 1$ JMP @RETAD ; End of file so jump to main program 1$: TSTB @#ERRWRD BNE 3$ ; End of file INC ESW 2$: RTS PC 3$: BITB #2,@#ERRWRD BNE 2$ ; Or file not found are allowed .PRINT #ERRMSG ; All else are bad .EXIT WERR: .PRINT #WERMSG ; Prints message if error in output file JMP @RETAD ; Return immediately to main prog .ENDC .IF DF R$$11M ; Get one byte of /CC argument. Enter with %5 pointing to lo or hi byte of ; COMMENT, and %0 pointing to the buffer containing a null or ASCII string. ; If the latter, the string is decoded as an octal byte value and stored where ; %5 points, unless the conversion fails, in which case the first character of ; the string is assumed to be the actual comment character itself. GETCCH: TSTB @%0 ; See if there is a string BEQ 1$ ; No, do nothing MOVB @%0,@%5 ; Yes, copy 1st ASCII char CLRB 5(%0) ; Make sure of a null terminator JSR PC,$COTB ; Try to convert ASCII octal value TSTB %2 ; if it was one? BNE 1$ ; Wasn't if number didn't terminate on a null MOVB %1,@%5 ; Yes it was, save octal byte 1$: RTS PC ; or return with 1st char if not .ENDC .PAGE ; Get character routines to select comments for various languages. ; Some of them are common to several languages, in which case the name of ; the routine is that of one of them. Differences may be set by the two ; bytes in COMMEN, which contains comment characters. ; RUNOFF files -- ignore text between . after newline or ;, and up to next ; newline or semicolon. RUNOFF: MOV R3,-(SP) JSR PC,@INTCPT ; Get next character BIT #CHCRLF,(SP)+ ; Was last char CR/LF/FF? BEQ RETCHR ; No so return 3$: CMPB COMMENT,R0 ; Is new character .? BNE RETCHR ; No so jump 1$: JSR PC,@INTCPT ; Keep getting next character until eol or ; BIT #10,R5 ; CR/LF/FF? BNE RETCHR ; Yes if set, return CMPB %0,COMMENT+1 ; ;? BNE 1$ ; No, keep ignoring JSR PC,@INTCPT ; Yes, get character after ; BR 3$ ; and go see if . ; Look at whole line starting with COMMENT hi, or any part after COMMENT lo: ; FORTRAN all of line starting C, or part after ! ; SAL all of line starting *, or part after ; FORTRAN:BIT #CHCRLF,%3 ; Was last character a new line? BEQ RETNXT ; No, return whatever is next JSR PC,@INTCPT ; Yes, get 1st character on line CMPB %0,COMMENT+1 ; Is it line starter character? BEQ RETNXT ; Yes, get rest of line BR MACRO3 ; No, look for COMMENT char ; Accept all of line after character in lo byte of COMMENT: ; MACRO character is ; ; AP120B character is " ; RATFOR character is # MACRO: BIT #CHCRLF,R3 ; Was last character a new line? BEQ RETNXT ; No, return next char MACRO2: JSR PC,@INTCPT ; Get next character MACRO3: CMPB COMMENT,R0 ; Look for general comment starter BNE MACRO2 ; Not found, keep looking BR RETNXT ; Return next char after comment char ; Accept text between characters COMMENT lo and COMMENT hi: ; RTL2 text between %'s. ; PASCAL text between { and }. ; Procedure is to use RTL2 to look for comment starter, then switch to ; RTL2X to return actual characters, returning to RTL2 when comment ; terminator is found. RTL2: JSR PC,@INTCPT ; Get next character CMPB COMMENT,R0 ; Look for start of comment BNE RTL2 ; Not found so loop MOV #RTL2X,GETCHR ; Change routine name RTL2X: JSR PC,@INTCPT ; Get next character CMPB COMMENT+1,R0 ; Test for end of comment BNE RETCHR ; No, return with character MOV #RTL2,GETCHR ; Yes, reset subroutine name BR RETERM ; and give a terminator ; Accept part of line after character pair in COMMENT lo + COMMENT hi: ; BCPL accept line after // BCPL: BIT #CHCRLF,%3 ; Was last end of line? BEQ RETNXT ; No, get character and return it 2$: JSR PC,@INTCPT ; Get character 1$: CMPB %0,COMMENT ; c.f. first char BNE 2$ ; No, keep looking JSR PC,@INTCPT ; Yes, get next CMPB %0,COMMENT+1 ; Is that second? BNE 1$ ; No, try for first RETNXT: JMP @INTCPT ; Return next character ; C -- return text between /* ... */. ; This is a mixture of the procedures for RTL2 and BCPL. C: JSR PC,@INTCPT ; Get a character CMPB %0,COMMENT ; is it 1st one of starter? BNE C ; No, keep looking JSR PC,@INTCPT ; Yes, get next CMPB %0,#'* ; is it * of /* ? BNE C ; No, keep looking MOV #CX,GETCHR ; Yes, change routines for next time ; Look for */ ending comment. CX: JSR PC,@INTCPT ; Get character CMPB %0,#'* ; Could it be start of comment end? BNE RETCHR ; No, return it JSR PC,@INTCPT ; Yes, look at the next CMPB %0,COMMENT+1 ; Is it the second comment ender? BNE 2$ ; No, still in comment MOV #C,GETCHR ; Yes, change back to C for next get BR RETERM ; and return a terminator 2$: INC CNT ; Found a * alone in comment, put back DEC BUFAD ; the character just read RETERM: MOV #SPACE,%0 ; Return a terminator JMP TSTCR ; and flags as INCHAR would do RETCHR: RTS PC ; Comment character found, return .IF DF RT11 INITIL: CLR BLK ; Initialises at start of new file .READ #EMTBUF,FILE,BUFFER+2,#256.,BLK ; Start first read BCC 1$ ; Jump if no errors JMP @RETAD ; Return to main prog as no file 1$: CLRB ESW ; End of file flag CLR CNT RTS PC .PSECT TEMP ; Open default dictionaries, if they exist. Set FILEN to the total number ; of blocks, as a guide to the dictionary space required. OPDEF: .FETCH FREE,#FLENM2 ; Opens default files MOV R0,FREE ; Store free space BCC 1$ .PRINT #FTCHER ; Print error message RTS PC ; Return with carry set 1$: .LOOKUP #EMTBUF,#10.,#FLENM1 ; Open file BCC 2$ .PRINT #DCTNAV ; Dictionary not found RTS PC 2$: MOV R0,FILEN ; Save file length of sys dictionary .LOOKUP #EMTBUF,#9.,#FLENM2 ; Open file BCS 3$ ; User dictionary not found CMP R0,FILEN ; Same length as system dictionary ? BNE 3$ ; No so jump, yes so probably sys dic .CLOSE #9. ; So close, don't load sys dic twice 3$: RTS PC .ENDC .IF DF R$$11M ; Open default dictionaries, LB:[1,2]SPELL.WRD, and SY:[g,m]SPELL.WRD, if ; they exist. Add total number of blocks into FILEN, as a guide to the ; dictionary space required. Leave DICFDB open on LB:[1,2]SPELL.WRD if ; it exists. OPDEF: JSR PC,USRDIC ; Try to open user dictionary JSR PC,5$ ; Do common processing CLOSE$ ; Close for the moment MOV #DICDSD,%2 ; Now try LB:[1,2]SPELL.WRD JSR PC,OPDSD ; by dataset descriptor 5$: BCC 10$ ; OK if open worked CMPB F.ERR(%0),#IE.NSF ; No such file? BEQ 20$ ; Yes, don't bother with file JMP OPNERR ; No, report other error and abandon 10$: ADD F.EFBK+2(%0),FILEN ; Open OK, store no of blocks 20$: RTS PC ; Return ; Try to open user dictionary file by filename block. USRDIC: FDOP$R #DICFDB,,,,#FO.RD ; Open for read by filename block CLR %2 ; without dataset descriptor, so use default FNB BR OPDSD ; open file and return ; General file open routine. This is a private version of .OPEN, calling ; .PARSE and .OPFNB manually, to avoid having both .OPFNB and .OPEN from Syslib. ; Enter with %0 addressing FDB. Destroys %1-%3. OPEN: MOV F.DSPT(%0),%2 ; Get default dataset descriptor from FDB ; Enter here when dataset descriptor pointer (or null) is already in %2. OPDSD: MOV %0,%1 ; Get pointer to ADD #F.FNB,%1 ; actual filename block, OPFNB: MOV F.DFNB(%0),%3 ; and default filename block from FDB JSR PC,.PARSE ; Fill in filename block, 5$: .IF DF DOUBUF BIT #DICT,CODE ; If this is a dictionary load BEQ 6$ FDBF$R ,,#<2*512.>,#2 ; we can double-buffer input BR 7$ ; as the output file buffer is not in use 6$: FDBF$R ,,#512,#1 ; Otherwise, must single-buffer .ENDC 7$: JSR PC,.OPFNB ; Open file BCC 10$ ; OK if it worked ; Test for shared access file open problems and retry if necessary. CMPB F.ERR(%0),#IE.LCK ; File locked? BEQ 5$ ; Yes, try again CMPB F.ERR(%0),#IE.NOD ; No pool space? BEQ 5$ ; Yes, try again again SEC ; No, set error flag 10$: RTS PC ; and return to caller .ENDC .PAGE .PSECT .IF DF RT11 NOWRDM: .ASCII <15><12><12>/Words in dictionary: /<200> FRELET: .ASCII /, Room for /<200> TERM: .ASCIZ / more letters./ WERMSG: .ASCIZ /?SPELL-F-Write error/ NEQ: .ASCIZ /?SPELL-F-Address error/ MEMOVF: .ASCIZ /?SPELL-F-Memory overflow/ ERRMSG: .ASCIZ /?SPELL-F-Read error/ WARMSG: .ASCII /?SPELL-W-/<200> .ENDC .IF DF R$$11M NOWRDM: .BYTE CR NWORDS: .ASCII " words in dictionary, room for " NMORE: .ASCIZ " more letters" NOWRDL=.-NOWRDM-1 QUERYM: .BYTE CR QUERYN: .ASCII " queries in " NTOTLM: .ASCIZ " words" QUERYL=.-QUERYM-1 NEQ: SEVERE: .ASCII <15>"SPE -- *SEVERE ERROR*-" SEVERL=.-SEVERE .ASCII "Internal consistency failure" NEQL=.-NEQ ERRORM: .ASCII <15>"SPE -- *ERROR*-" ERRORL=.-ERRORM CMDERM: .ASCII "Faulty command line" CMDERL=.-CMDERM OPNERM: .ASCII "File open error ." OPNERL=.-OPNERM WERMSG: .ASCII "File write error ." WERMGL=.-WERMSG INPERM: .ASCII "File read error ." INPERL=.-INPERM MEMOVF: .ASCII "Memory overflow" MEMOVL=.-MEMOVF LIMMSS: WARMSG: .ASCII <15>"SPE -- *WARNING*-" WARMGL=.-WARMSG .ASCII "Limited memory, dictionary words >= " LIMMSN: .ASCII " letters not loaded" LIMMSL=.-LIMMSS LOADIN: .ASCII "Loading dictionary" DOT: .ASCII "." ; Repeated '.' as dictionary load proceeds LOADL=.-LOADIN LOADQ: .ASCII <15>/Load "/ ; Start of Load "word" message LOADQL=.-LOADQ YNGQ: .ASCII @" [Yes/No/Go/Quit] ? @ ; End of prompt YNGQL=.-YNGQ RECNO: .ASCIZ "[ ] " ; Space to form record number .ENDC .EVEN .IIF DF RT11,DEFLT: .RAD50 "RNOLSTWRD " SAVECH: .WORD 0 ; Save last character if peeped at LINPOS: .WORD 0 ; Current position on line when outputting LINLEN: .WORD 72. ; Maximum chars on output dictionary line .IF DF DICSPC MEMLIM: .WORD DICST+DICSPC ; End of dictionary area .IFF MEMLIM: .WORD 0 ; Top limit of free memory (to be found on startup) .ENDC MEMMAX: .WORD 0 ; Absolute maximum memory available (by INS/INC if reqd) CURLEN: .WORD 0 ; Length of current word FLETST: .WORD 0 ; DeASCIIed first letter in word SLETST: .WORD 0 ; DeASCIIed second letter in word SSEARC: .WORD 0 ; Start of search area ESEARC: .WORD 0 ; End of search area CORRES: .WORD 0 ; Maximum correspondence count when guessing NOWRDS: .WORD 0 ; Count of words in dictionary TOTWRD: .WORD 0 ; Count of words in source file ANSWER: .WORD 0 ; Answer to Load query .IIF DF RT11,OFLBLK: .WORD 0 ; Block/record pointer for output file OFLPTR: .WORD OUTBUF ; Output buffer pointer OFLCNT: .WORD 512. ; Output buffer count .IIF DF RT11,OFILE: .WORD 0 ; Output file number FILEN: .WORD 0 ; Length of dictionary file LIMLEN: .WORD MXWORD ; If limited memory then max length of words MINLEN: .WORD 1 ; Minimum length of words user wants LNFLG: .WORD 0 ; Flag for controlling dictionary output format FMFLG: .WORD 0 ; LNFLG clear if just done CR/LF, FMFLG clear if FF .IIF DF RT11,FREE: .WORD DEVS .IF DF R$$11M .IF NDF DICSPC SPSAVE: .LIMIT ; Space for stack pointer FREE=.-2 ; and top of task code .IFF SPSAVE: .WORD 0 ; Space for stack pointer FREE: .WORD DICST ; Start of dictionary space .ENDC IFLFDB: .WORD DICFDB ; Current input file FDB -- INFDB or DICFDB TIDEV: .WORD 0 ; TI: device, and TIUNIT: .WORD 0 ; unit number, set on startup GOTDD: .WORD 0 ; Flags default dictionaries loaded and unchanged .ENDC INTCPT: .WORD INCHAR ; Holds routine to deal with input file format INROUT: .WORD NULL ; Holds routine to deal with input file format GETCHR: .WORD NULL ; Routine which provides next character COMMEN: .WORD '; ; Comment character for MACRO programs FSTLET: .BLKW 27. ; Buffer for addresses of first letters SLETAD: .WORD 0,50.,100.,150.,200.,250.,300.,350.,400.,450.,500. .WORD 550.,600.,650.,700.,750.,800.,850.,900.,950. .WORD 1000.,1050.,1100.,1150.,1200.,1250. LETCNT: .WORD 0 CODE: .WORD 21 ; Holds current situation and flags AUXSWD: .WORD WIBIT ; Auxiliary switch word:- UCBIT=40 ; /UpperCase dictionary output (** bit 5 in lo byte **) ; Only UCBIT may be in lo byte -- all others must be in hi: IPBIT=400 ; Bit 8 set if embedded punctuation should not be queried WIBIT=1000 ; Bit 9 set if 1 query/line, clear if 3 IUBIT=100000 ; Bit 15 set if all-UC words should be ignored .IF DF RT11 BUFFER: .WORD BUF1,BUF2 ; Address of input buffers FILE: .WORD 0 ; Number of current file in use BLK: .WORD 0 ; Block last read in input file .ENDC CNT: .WORD 0 ; Number of bytes left in input buffer BUFAD: .WORD 0 ; Current position in input buffer ESW: .WORD 0 ; Flag to show eof next block .PAGE ; Bit 0 Punctuation mark ; Bit 1 Up arrow or backslash ; Bit 2 character ; Bit 3 carriage return/line feed ; Bit 4 lower case letter ; Bit 5 upper case letter ; Bit 6 word end ; Bit 7 word start .RADIX 2 TABLE: .BYTE 01000000,01000000,01000000,01000000 .BYTE 01000000,01000000,01000000,01000000 .BYTE 01000000,11000000,11001000,11000000 ; Line feed .BYTE 11001000,11001000,01000000,01000000 ; CR,FF .BYTE 01000000,01000000,01000000,01000000 .BYTE 01000000,01000000,01000000,01000000 .BYTE 01000000,01000000,01000000,01000000 .BYTE 01000000,01000000,01000000,01000000 .BYTE 11000000,11000001,11000001,11000000 ; SP,!,",# .BYTE 11000000,11000000,11000000,11000001 ; $,%,&,' .BYTE 11000000,11000000,11000000,11000000 ; (,),*,+ .BYTE 11000001,11000000,11000001,11000000 ; ,,-,.,/ .BYTE 00000000,00000000,00000000,00000000 ; 0,1,2,3 .BYTE 00000000,00000000,00000000,00000000 ; 4,5,6,7 .BYTE 00000000,00000000,11000001,11000000 ; 8,9,:,; .BYTE 11000000,11000000,11000000,11000001 ; <,=,>,? .BYTE 11000000,00100100,00100100,00100100 ; @,A,B,C .BYTE 00100100,00100100,00100100,00100100 ; D,E,F,G .BYTE 00100100,00100100,00100100,00100100 ; H,I,J,K .BYTE 00100100,00100100,00100100,00100100 ; L,M,N,O .BYTE 00100100,00100100,00100100,00100100 ; P,Q,R,S .BYTE 00100100,00100100,00100100,00100100 ; T,U,V,W .BYTE 00100100,00100100,00100100,11000000 ; X,Y,Z,[ .BYTE 11000010,11000000,11000010,11000000 ; \,],^,_ .BYTE 11000000,00010100,00010100,00010100 ; `,a,b,c .BYTE 00010100,00010100,00010100,00010100 ; d,e,f,g .BYTE 00010100,00010100,00010100,00010100 ; h,i,j,k .BYTE 00010100,00010100,00010100,00010100 ; l,m,n,o .BYTE 00010100,00010100,00010100,00010100 ; p,q,r,s .BYTE 00010100,00010100,00010100,00010100 ; t,u,v,w .BYTE 00010100,00010100,00010100,11000000 ; x,y,z,{ .BYTE 11000000,11000000,11000000,11000000 ; |,},~, .RADIX 8 .IF DF RT11 .PSECT TEMP FLENM1: .RAD50 "SY SPELL WRD" FLENM2: .RAD50 "DK SPELL WRD" FTCHER: .ASCIZ /Spell - Driver missing/ DCTNAV: .ASCIZ /SY:SPELL.WRD not found/ LIMMSS: .ASCII /Limited memory - Dictionary words >= /<200> ELMMSS: .ASCIZ / letters not loaded/ HLPTXT: .ASCII ;*{F1.LST}{,F2.WRD}=F3.RNO,{Fn.RNO,etc}/switches; .ASCII ; F1.LST Contains all words in source not in dictionary; .ASCII ; F2.WRD Contains all words in source & dictionary; .ASCII ; F3.RNO Contains words to be checked; .ASCII ; Fn.RNO Up to 5 dictionary files; .ASCII ;General Switches:; .ASCII ; /B Ignore emBedded punctuation; .ASCII ; /C:n Consider only words of >n letters; .ASCII ; /D Dictionaries SY:SPELL.WRD,DK:SPELL.WRD are not used; .ASCII ; /E Every error is printed (not once for each word); .ASCII ; /G Inhibit Guessing of unknown words; .ASCII ; /I Inhibit word matching; .ASCII ; /K Don't check all-upper-case words; .ASCII ; /N:n Output files are limited to n chars per line; .ASCII ; /P Pack 3 errors per line; .ASCII ; /Q Query whether to load each unknown word; .ASCII ; /S:n Space for >n letters after loading system dictionary; .ASCII ; /U Outputs dictionary in upper case; .ASCII ;Language switches to select comments only (default /R):; .ASCII ; /A = AP120B, /F = FORTRAN, /J = C, /L = Pascal, /M = MACRO; .ASCII ; /R = RUNOFF, /T = RTL2, /W = RATFOR, /X = text, /Y = BCPL, /Z = SAL, ; .ASCIZ ;By default & for all dictionary files all text is examined; TTLE: .ASCIZ ;Spelling check (/H for help); .ENDC .IF NDF M$$EIS MUL: MOV R0,-(SP) ; R3&R4=R4*R5 MOV #17.,R0 ; Count CLR R3 ; Top 16 bits of answer 1$: ROR R3 ROR R4 BCC 2$ ADD R5,R3 2$: DEC R0 BNE 1$ MOV (SP)+,R0 RTS PC .ENDC FRESPC: .WORD MINFRE ; Minimum free space after sys dic loaded NUMWRD: .WORD 0 ; End of list .WORD 2550. ; Fraction of letters in dic in words of <=4 let .WORD 6942. ; Fraction of letters in dic in words of <=5 let .WORD 13457. ; Fraction of letters in dic in words of <=6 let .WORD 22359. ; Fraction of letters in dic in words of <=7 let .WORD 32278. ; Fraction of letters in dic in words of <=8 let .WORD 41979. ; Fraction of letters in dic in words of <=9 let .WORD 50548. ; Fraction of letters in dic in words of <=10 let .WORD 56711. ; Fraction of letters in dic in words of <=11 let .WORD 61048. ; Fraction of letters in dic in words of <=12 let .WORD 63648. ; Fraction of letters in dic in words of <=13 let .WORD 64646. ; Fraction of letters in dic in words of <=14 let .WORD 65324. ; Fraction of letters in dic in words of <=15 let .IF DF R$$11M HLPTXT: .ASCII ">SPE {{f1.LST{,f2.WRD}=}{f3.RNO}{,fn.WRD,...}/switches" TICRLF: .BYTE CR,LF .ASCII ; f1.LST Queried words f2.WRD New dictionary; .ASCII ; f3.RNO Source for checking fn.WRD Dictionary files; .ASCII ;General Switches (default /IG:1/-IU/-IP/EV/GU/-QU/LE:72/WI/SP/-KD):-; .ASCII ; /CC:c{:d} Change comment character(s) to c {& d}; .ASCII ; /IG:n Ignore words of <= n letters ; .ASCII ; /IU Ignore words wholly in upper case; .ASCII ; /IP Ignore punctuation embedded in words; .ASCII ; /DD Use default dictionaries LB:[1,2]SPELL.WRD & SY:SPELL.WRD; .ASCII ; /KD Keep dictionary for next input file; .ASCII ; /EV=/-LO Every query is printed, none loaded into dictionary; .ASCII ; /GU Guess unknown words; .ASCII ; /QU Query before loading each unknown word; .ASCII ; /LE:n Output files are limited to n chars per line; .ASCII ; /WI List 3 queries per line; .ASCII ; /FR:n Space for >n letters after loading system dictionary; .ASCII ; /UC Outputs dictionary in upper case; .ASCII ; /SP Spool differences file; .ASCII ; /LA Latch switches for next command line; .ASCII ;Language switches to select comments only (default per f3 filetype):; .ASCII ; /AP = AP120B, /MA = MACRO, /PA = Pascal, /RU = RUNOFF, /FO = FORTRAN; .ASCII ; /RA = RATFOR, /RT = RTL2, /SA = SAL, /C = C, /BC = BCPL, /TE = text; HLPLEN=.-HLPTXT .EVEN .ENDC .PSECT TEMP,RW,D,REL ; The following macro calls define work space which ; overlays PSECT TEMP. TEMP contains executable code ; which must not be destroyed until finished with .IIF DF RT11, ; but also loads and uses EMTBUF and DEVS. .=TEMP ; Set to start of TEMP PSECT .IF DF R$$11M DEFINE IOSTAT,4 ; Terminal I/O status block DEFINE INBUF,BUFLEN ; I/O buffer for source file DEFINE OUTBUF,BUFLEN ; Buffer for output file DEFINE CSIBLK,C.SIZE ; CSI control block .ENDC DEFINE QUERYS,2 ; Queried words counter DEFINE RECORD,2 ; Source records (lines) counter DEFINE WRDBUF,MXWORD ; Buffer for incoming words DEFINE CMPBUF,MXWORD ; Buffer for comparison .IF DF RT11 DEFINE BUF1,512. DEFINE BUF2,512. DEFINE OUTBUF,512. ; Space for output file DEFINE QQQQ,<28.> ; 2 extra queue elements .ENDC DEFINE SNDLET,<50.*26.>; Offsets of second letters .IF DF RT11 DEFINE EMTBUF,20 ; Space for EMT calls DEFINE DEVS,0 ; Free memory .ENDC .IIF DF DICSPC, DEFINE DICST,DICSPC ; Dictionary area DEFINE LSISTI,1 ; Flag to show if listing on user's terminal DEFINE FILES,1 ; Flag to show if any files on command line .IF DF R$$11M .=TEMP+TOTLEN .EVEN .PSECT DATA,D,RW,LCL ; Read-write local data area ; Set up lookup table and bit definitions for language switches. .MACRO LANGWG SWITCH,FTYPE,SUBR,COMCHR SWITCH'BIT=$$$ $$$=$$$*2 NLANG=NLANG+1 .WORD ^R'FTYPE,SUBR,COMCHR .ENDM LANGWG $$$=1 ; Switch bits start at bit 0 NLANG=0 ; Clear counter LNGTAB: LANGWG TE,TXT,NULL,0 ; Straight text LANGWG RU,RNO,RUNOFF,<".;> ; RUNOFF LANGWG SA,SAL,FORTRAN,<";*> ; SAL LANGWG FO,FTN,FORTRAN,<"!C> ; FORTRAN LANGWG MA,MAC,MACRO,<';> ; MACRO LANGWG C,,C,<"//> ; C LANGWG PA,PAS,RTL2,<"{}> ; Pascal LANGWG CM,CMD,MACRO,<';> ; Command files LANGWG BC,BPL,BCPL,<"//> ; BCPL LANGWG AP,AP1,MACRO,<'"> ; AP120B LANGWG RA,RAT,MACRO,<'#> ; RATFOR LANGWG RT,RTL,RTL2,<"%%> ; RTL2 ; Bit definitions for general switches. (SWWRD). LEBIT=2 ; /LEngth:n -- dictionary line length KDBIT=4 ; /KeepDictionary from last time GUBIT=NGUESS ; /GUess words not found (** must be bit 3) EVBIT=NLOAD ; /EVery occurrence of error to be listed (** bit 4) LOBIT=EVBIT ; /LOad unknown words into dictionary <=> /-EV IGBIT=100 ; /Ignore:n length of words to ignore DDBIT=200 ; /DefaultDictionaries to be loaded (** bit 8 **) SPBIT=400 ; /SPool errors output FRBIT=1000 ; /FRee:n space required after dictionary load CCBIT=2000 ; /CommentCharacter:char1:char2 to change defaults QUBIT=ASK ; /QUery words to be loaded into dictionary ; /HE, /LA, and /BK may appear alone on a command line, must be different from ; any language bit so a "No =" error message can be suppressed. HEBIT=20000 ; /HElp LABIT=40000 ; /LAtch switches BKBIT=100000 ; /BreaK to ODT (must be bit 15) ; General switches. SWTAB: CSI$SW LE,LEBIT,SWWRD,SET,,LEDES ; /LEngth:n CSI$SW KD,KDBIT,SWWRD,SET,NEG ; /KeepDictionary CSI$SW GU,GUBIT,SWWRD,CLEAR,NEG ; /GUess CSI$SW EV,EVBIT,SWWRD,CLEAR,NEG ; /EVery CSI$SW LO,LOBIT,SWWRD,SET,NEG ; /LOad <=> /-EVery CSI$SW IG,IGBIT,SWWRD,SET,,IGDES ; /IGnore:n CSI$SW DD,DDBIT,SWWRD,CLEAR,NEG ; /DefaultDictionaries unless bit set CSI$SW SP,SPBIT,SWWRD,CLEAR,NEG ; /SPool unless bit set CSI$SW QU,QUBIT,SWWRD,SET,NEG ; /QUery words to be loaded CSI$SW FR,FRBIT,SWWRD,SET,,FRDES ; /FRee:n CSI$SW HE,HEBIT,SWWRD,SET,NEG ; /HElp CSI$SW LA,LABIT,SWWRD,SET,NEG ; /LAtch CSI$SW BK,BKBIT,SWWRD,SET,NEG ; /BreaK ; Auxiliary switches: CSI$SW WI,WIBIT,AUXSWD,CLEAR,NEG ; /WIde if bit clear CSI$SW IP,IPBIT,AUXSWD,SET,NEG ; /Ignore embedded Punctuation if set CSI$SW IU,IUBIT,AUXSWD,SET,NEG ; /IgnoreUppercase words CSI$SW UC,UCBIT,AUXSWD,SET,NEG ; /UpperCase dictionary output ; Language switches. CSI$SW CC,CCBIT,LANG,SET,NEG,CCCDES ; /CommentCharacter:char1{:char2} CSI$SW RU,RUBIT,LANG,SET,NEG ; /RUnoff CSI$SW SA,SABIT,LANG,SET,NEG ; /SAl CSI$SW FO,FOBIT,LANG,SET,NEG ; /FOrtran CSI$SW MA,MABIT,LANG,SET,NEG ; /MAcro CSI$SW C,CBIT,LANG,SET,NEG ; /C CSI$SW PA,PABIT,LANG,SET,NEG ; /PAscal CSI$SW BC,BCBIT,LANG,SET,NEG ; /BCpl CSI$SW AP,APBIT,LANG,SET,NEG ; /AP120b CSI$SW RA,RABIT,LANG,SET,NEG ; /RAtfor CSI$SW RT,RTBIT,LANG,SET,NEG ; /RTl2 CSI$SW TE,TEBIT,LANG,SET,NEG ; /TExt CSI$ND ; Switch value tables. IGDES: CSI$SV DECIMAL,MINLEN,2 ; /IG:minlen CSI$ND CCCDES: CSI$SV ASCII,INBUF,5 ; /CC:cchar:cchar CSI$SV ASCII,INBUF+6,5 ; Values may be octal, or single char CSI$ND LEDES: CSI$SV DECIMAL,LINLEN,2 ; /LE:line length CSI$ND FRDES: CSI$SV DECIMAL,FRESPC,2 ; /FR:free space CSI$ND TIQIOW: QIOW$ IO.CCO,TILUN,TILUN,,IOSTAT,,<,,40> ; Terminal message QIO .IF DF T$$RPR ASKOP: QIOW$ IO.RPR,TILUN,TILUN,,IOSTAT,, .IFF ASKOP: QIOW$ IO.RLB,TILUN,TILUN,,IOSTAT,, .ENDC .IIF DF P$$OFF,EXSTAT: .WORD EX$SUC ; Exit status, assume success SWWRD: .WORD 0 ; Switch word LANG: .WORD 0 ; Language switch word KEEPD: .WORD 0 ; Mask to prevent using /KD first time, ; set to KDBIT for second and later runs FSRSZ$ 2,,DATA ; 2 files open GC: GCMLB$ 1,SPE ; GCML control block ; Dictionary input and all outputs. DICFDB: OUTFDB: FDBDF$ ; Set up file descriptor block FDAT$A R.VAR,FD.CR FDRC$A FD.PLC,OUTBUF,BUFLEN FDOP$A OUTLUN,CSIBLK+C.DSDS,OUTDEF OUTDEF: NMBLK$ SPELL,WRD,0,SY,0 ; Default dictionaries SY0:[g,m]SPELL.WRD;0 DICDEV: .ASCII "LB:" ; and LB:[1,2]SPELL.WRD DDVLEN=.-DICDEV DICUIC: .ASCII "[1,2]" DUILEN=.-DICUIC DICNAM: .ASCII "SPELL.WRD" DNMLEN=.-DICNAM TI0DEV: .ASCII "TI:" TI0LEN=.-TI0DEV .EVEN DICDSD: .WORD DDVLEN,DICDEV,DUILEN,DICUIC,DNMLEN,DICNAM ; Dataset descriptor TI0DSD: .WORD TI0LEN,TI0DEV,0,0,0,0 ; TI0: dataset descriptor ; Source text input. INFDB: FDBDF$ FDAT$A R.VAR,FD.CR FDRC$A FD.PLC,INBUF,BUFLEN FDOP$A INLUN,CSIBLK+C.DSDS,INDEF,FO.RD INDEF: NMBLK$ SPELL,RNO,0,SY,0 ; Default input filename SY0:SPELL.RNO;0 DEFTYP=INDEF+N.FTYP ; Filetype may be changed .ENDC .END SPELL