10000 '***********************************
10010 '* PROGRAM CHASM    Version 2.01   *
10020 '*                                 *
10030 '* CHeap ASseMbler for the IBM PC. *
10040 '*                                 *
10050 '* Begun 6/15/82 by Dave Whitman   *
10060 '***********************************
10070 '
10080 'main program
10090    GOSUB 50000   'initialize
10100   'wipe out transient code
10110   CHAIN MERGE "chasm.ovl",10120,ALL,DELETE 50000-51570
10120   GOSUB 19950   'set up sym table
10130   GOSUB 10170   'pass 1: build sym table
10140   GOSUB 10380   'pass 2: generate obj code & listing
10150   GOSUB 19490   'clean up
10160 SYSTEM
10170 '*******************************************
10180 '* SUBROUTINE PASSONE                      *
10190 '* Adds user-defined symbols to sym table. *
10200 '*******************************************
10210 '
10220 PASS = 1
10230 LOCTR = 256   '0-255 reserved for p.s. prefix
10240 LINENUM = 0
10250 WHILE NOT EOF(1)
10260  'get source line, initialize
10270    GOSUB 10620   'getline
10280  'parse it
10290    GOSUB 10730  'parse
10300  'if label, enter in sym table
10310    IF LABEL$ <> "" THEN GOSUB 11640  'newentry
10320  'if op, decode, & update loctr
10330    IF OP$ <> "" THEN GOSUB 12480   'update_loctr
10340  'progress report
10350    GOSUB 19850
10360  WEND
10370 RETURN
10380 '*********************************
10390 '* SUBROUTINE PASSTWO            *
10400 '* Generates obj code & listing. *
10410 '*********************************
10420 '
10430 GOSUB 19370  'pass2_init
10440 '
10450 WHILE NOT EOF(1)
10460  'get source line, initialize
10470    GOSUB 10620   'getline
10480  'parse line
10490    GOSUB 10730   'parse
10500  'phase error?
10510    IF LABEL$ <> "" THEN GOSUB 11910  'check_phase
10520  'if op, update loctr, generate obj. code
10530    IF OP$ <> "" THEN GOSUB 12480   'update_loctr
10540  'output obj. code & listing line
10550    GOSUB 19020  'output
10560  'progess report
10570    GOSUB 19850
10580  WEND
10590 'wipe out msg
10600   X = POS(0): Y = CSRLIN: LOCATE 25,1: PRINT TAB(79): LOCATE Y,X
10610 RETURN
10620 '********************************************
10630 '* SUBROUTINE GETLINE                       *
10640 '* Gets line of source code for processing. *
10650 '* and initializes for new iteration.       *
10660 '********************************************
10670 '
10680 LINE INPUT#1, INPLINE$
10690 LINENUM = LINENUM + 1
10700 NEEDOFFSET = NONE: DSFLAG = FALSE
10710 OBJLEN = 0
10720 RETURN
10730 '*****************************************************
10740 '* SUBROUTINE PARSE                                  *
10750 '* Parses input line for any label, op, or operands. *
10760 '*****************************************************
10770 '
10780 LINEPTR = 1: LINEPTR2 = 1
10790 LABEL$ = "": OP$ = "": SOURCE$ = "": DEST$ = ""
10800 '
10810 'set endptr to end of code
10820   ENDPTR = INSTR(INPLINE$,";") - 1            'just before comment
10830   IF ENDPTR = -1 THEN ENDPTR = LEN(INPLINE$)  'no comment, set to eol
10840 '
10850 'no code? (return)
10860   IF ENDPTR = 0 THEN 11120
10870 '
10880 'convert to all caps
10890   GOSUB 11140
10900 '
10910 'label (if any)
10920   IF INSTR(DELIM$,LEFT$(INPLINE$,1))  THEN 10960
10930     GOSUB 11280  'getfield
10940     LABEL$ = FLD$
10950 '
10960 'op-code
10970   GOSUB 11280  'getfield
10980   IF NOT FOUND THEN 11120
10990     OP$ = FLD$
11000 'save ptr to start of operands
11010   OPDPTR = LINEPTR
11020 '
11030 'destination operand (if any)
11040   GOSUB 11280  'getfield
11050   IF NOT FOUND THEN 11120
11060   DEST$ = FLD$
11070 '
11080 'source operand (if any)
11090   GOSUB 11280  'getfield
11100   IF NOT FOUND THEN 11120
11110   SOURCE$ = FLD$
11120 RETURN
11130 '
11140 'internal subroutine caps
11150 'Scans inpline$ up to comment field,
11160 'converting l.c. chars. to u.c.. Skips over strings.
11170 FOR I = 1 TO ENDPTR
11180   C$ = MID$(INPLINE$,I,1)
11190   'skip strings
11200     IF C$ <> "'" THEN 11240
11210       STRGEND = INSTR(I+1,INPLINE$,C$)
11220       IF STRGEND > 0 THEN I = STRGEND: GOTO 11250
11230   'convert
11240     IF ASC(C$) => 97 AND ASC(C$) <= 122 THEN C$ = CHR$(ASC(C$) - 32):                  MID$(INPLINE$,I,1) = C$
11250   NEXT I
11260 RETURN
11270 '***********************************************************
11280 '* SUBROUTINE GETFIELD                                     *
11290 '* Starting at lineptr, trys to return next field in FLD$. *
11300 '* Sets found if sucessful. Moves lineptr past field.      *
11310 '***********************************************************
11320 '
11330 'find next non-delimiter or run off end
11340  WHILE LINEPTR <= ENDPTR
11350    IF INSTR(DELIM$,MID$(INPLINE$,LINEPTR,1)) = 0 THEN 11380
11360    LINEPTR = LINEPTR + 1
11370    WEND
11380 'if past end, not found
11390  IF LINEPTR <= ENDPTR  THEN 11420
11400    FOUND = FALSE
11410    RETURN
11420 '
11430 'strings terminated by '
11440  IF MID$(INPLINE$,LINEPTR,1) <> "'" THEN 11500
11450    STRGEND = INSTR(LINEPTR+1,INPLINE$,"'")
11460    IF STRGEND = 0 THEN 11500
11470      LINEPTR2 = STRGEND + 1
11480      GOTO 11570
11490 '
11500 'otherwise, find next delimter or go 1 past end
11510  LINEPTR2 = LINEPTR
11520  WHILE LINEPTR2 <= ENDPTR
11530    IF INSTR(DELIM$,MID$(INPLINE$,LINEPTR2,1)) > 0 THEN 11570
11540    LINEPTR2 = LINEPTR2 + 1
11550    WEND
11560 '
11570 'copy field
11580  FLD$ = MID$(INPLINE$,LINEPTR,LINEPTR2-LINEPTR)
11590 '
11600 'move lineptr past field, set found & return
11610  LINEPTR = LINEPTR2
11620  FOUND = TRUE
11630  RETURN
11640 '**********************************************
11650 '* SUBROUTINE NEWENTRY                        *
11660 '* Adds new symbol to sym table with default  *
11670 '* attributes. (may be changed by pseudo-ops) *
11680 '**********************************************
11690 '
11700 'already in table? (error)
11710   TARGET$ = LABEL$
11720  GOSUB 12030     'operand_lookup
11730  IF NOT FOUND THEN 11780
11740    ERRS = ERRS + 1
11750    PRINT#2,"****Error: Duplicate definition of ";LABEL$;" in ";LINENUM
11760    RETURN
11770 '
11780 'table full? (error)
11790  IF NUMSYM < MAXSYM THEN 11840
11800    ERRS = ERRS + 1
11810    PRINT#2, "****Error: Too many user symbols in "; LINENUM
11820    RETURN
11830 '
11840 'else make new entry
11850  NUMSYM = NUMSYM + 1
11860  SYM$(NUMSYM) = LABEL$
11870  VAL1(NUMSYM) = LOCTR
11880  SYMTYPE(NUMSYM) = NEAR
11890 '
11900 RETURN
11910 '*********************************
11920 '* SUBROUTINE CHECK_PHASE        *
11930 '* Label value same both passes? *
11940 '*********************************
11950 IF OP$ = "EQU" THEN 12020
11960 TARGET$ = LABEL$
11970 GOSUB 12030  'operand_lookup
11980 '
11990 IF (SYMTYPE(TABLEPTR) AND (NEAR OR MEM)) = FALSE THEN 12020
12000   IF VAL1(TABLEPTR) = LOCTR THEN 12020
12010     ERRS = ERRS + 1: PRINT#2, "****Phase Error"
12020 RETURN
12030 '*************************************************
12040 '* SUBROUTINE OPERAND_LOOKUP                     *
12050 '* Trys to find TARGET$ in sym table.  If there, *
12060 '* sets FOUND true, & TABLEPTR to its'position.  *
12070 '*************************************************
12080 'scan table for symbol
12090   FOR TABLEPTR = 1 TO NUMSYM
12100     IF SYM$(TABLEPTR) = TARGET$ THEN 12160 'found
12110     NEXT TABLEPTR
12120 '
12130 'failure exit point
12140   FOUND = FALSE
12150   RETURN
12160 'sucess exit point
12170   FOUND = TRUE
12180   RETURN
12190 '*********************************************************
12200 '* SUBROUTINE LOOKUP_OP                                  *
12210 '* Given op-code in op$, & operand types in dtype &      *
12220 '* stype, trys to find op in opcode table. If sucessful, *
12230 '* sets found true, & opptr to its' position.            *
12240 '*********************************************************
12250 'binary search for good starting pt.
12260  MOVE = NUMOP: ST = MOVE/2
12270  WHILE MOVE >= 2
12280    MOVE = MOVE/2
12290    IF OP$ > OPCODE$(ST) THEN ST = ST + MOVE ELSE ST = ST - MOVE
12300    IF ST < 1 THEN ST = 1
12310    IF ST > NUMOP THEN ST = NUMOP
12320    WEND
12330 '
12340 'scan for entry matching all 3 fields
12350  FOR OPPTR = ST TO NUMOP
12360    IF OPCODE$(OPPTR) > OP$ THEN 12420   'failed
12370    IF OPCODE$(OPPTR) <> OP$ THEN 12410
12380    IF (SRCTYPE(OPPTR) AND STYPE) = FALSE THEN 12410
12390    IF (DSTTYPE(OPPTR) AND DTYPE) = FALSE THEN 12410
12400    GOTO 12450 'found!
12410    NEXT OPPTR
12420 'failure exit
12430  FOUND = FALSE
12440  RETURN
12450 'successful exit
12460  FOUND = TRUE
12470  RETURN
12480 '***************************************
12490 '* SUBROUTINE UPDATE_LOCTR             *
12500 '* Decodes operation & advances loctr. *
12510 '* On pass 2, generates obj. code.     *
12520 '***************************************
12530 '
12540 'set operand types & values
12550   'destination operand
12560    TARGET$ = DEST$: GOSUB 12860   'type_operand
12570    DTYPE = TARGTYPE
12580    DVAL1 = TARGVAL1
12590    DVAL2 = TARGVAL2
12600   'source operand
12610     'special case: RET op
12620      IF OP$ = "RET" THEN STYPE = PROCTYPE(STKTOP): GOTO 12690
12630     'normal source
12640      TARGET$ = SOURCE$: GOSUB 12860   'type_operand
12650      STYPE = TARGTYPE
12660      SVAL1 = TARGVAL1
12670      SVAL2 = TARGVAL2
12680 '
12690 'find op in op table (not there: error)
12700  TARGET$ = OP$
12710  GOSUB 12190   'lookup_op
12720  IF FOUND THEN 12810
12730    IF PASS = 1 THEN RETURN
12740    ERRS = ERRS + 1: PRINT#2,"****Syntax Error: ";OP$;DTYPE;STYPE
12750    IF ((ACUM8 OR ACUM16 OR REG8 OR REG16 OR SEG OR CS)                                AND (DTYPE OR STYPE)) THEN 12800
12760      IF (STYPE AND (NONE OR IMMED8 OR IMMED16)) = FALSE THEN 12800
12770        IF INSTR("BW",RIGHT$(OP$,1)) <> 0 THEN 12800
12780          DIAG = DIAG + 1
12790          PRINT#2,"****Diagnostic: Specify word or byte operation"
12800    RETURN
12810  FLAG = OFLAG(OPPTR)
12820 '
12830 'branch for mach ops & pseudo-ops to update loctr
12840  IF FLAG AND MACHOP THEN GOSUB 15160 ELSE GOSUB 15970
12850 RETURN
12860 '*********************************************************
12870 '* SUBROUTINE TYPE_OPERAND                               *
12880 '* Sets TARGTYPE to reflect TARGET$'s type.  Sets        *
12890 '* TARGVAL1 to its' value. If the operand is a register, *
12900 '* sets TARVAL2 to its' val2. If an offset appears,      *
12910 '* NEEDOFFSET gets the its' type, and OFFSET its' value. *
12920 '*********************************************************
12930 '
12940 'any operand?
12950  IF LEN(TARGET$) > 0 THEN 12980
12960    TARGTYPE = NONE
12970    RETURN
12980 'in sym table?
12990  GOSUB 12030   'operand_lookup
13000  IF NOT FOUND THEN 13050
13010    TARGTYPE = SYMTYPE(TABLEPTR)
13020    TARGVAL1 = VAL1(TABLEPTR)
13030    IF TABLEPTR <= PREDEF THEN TARGVAL2 = VAL2(TABLEPTR)
13040    RETURN
13050 'number?
13060  GOSUB 13440   'test_number
13070  IF NOT FOUND THEN 13110
13080    TARGTYPE = NUMTYPE
13090    TARGVAL1 = NUMVAL
13100    RETURN
13110 'direct mem. ref.?
13120  GOSUB 13820   'memref
13130  IF NOT FOUND THEN 13170
13140    TARGTYPE = MEM
13150    TARGVAL1 = MEMADDR
13160    RETURN
13170 'offset off register?
13180  GOSUB 14180   'parse_disp_off_reg
13190  IF NOT FOUND THEN 13240
13200    TARGTYPE = MEMREG
13210    TARGVAL1 = REGVAL
13220    RETURN
13230 'offset?
13240  GOSUB 14750 'offset
13250  IF NOT FOUND THEN 13290
13260    TARGTYPE = OFFSETYPE
13270    TARGVAL1 = OFFSETVAL
13280    RETURN
13290 'charactor?
13300  GOSUB 15050
13310  IF NOT FOUND THEN 13350
13320     TARGTYPE = IMMED8 OR IMMED16
13330     TARGVAL1 = CHARVAL
13340     RETURN
13350 'string?
13360  IF LEFT$(TARGET$,1) <> "'" THEN 13400
13370    TARGTYPE = STRING
13380    RETURN
13390 '
13400 'not found? assume near label or mem ref. (error on pass 2)
13410  IF PASS = 2 THEN PRINT#2,"****Error: Undefined symbol ";TARGET$:                  ERRS = ERRS + 1
13420  TARGTYPE = NEAR OR MEM
13430 RETURN
13440 '*******************************************
13450 '* SUBROUTINE TEST_NUMBER                  *
13460 '* Trys to interpret TARGET$ as a number.  *
13470 '* If sucessful, sets FOUND true, NUMVAL   *
13480 '* to its' value and NUMTYPE to its' type. *
13490 '*******************************************
13500 '
13510 FOUND = FALSE
13520 TN$ = TARGET$  'working copy
13530 '
13540 'hex number?
13550  IF RIGHT$(TN$,1) <> "H" THEN 13690
13560   'lop off H
13570    TN$ = LEFT$(TN$,LEN(TN$)-1)
13580   'scan for non-hex digits (exit)
13590    I = 1
13600    FOR I = 1 TO LEN(TN$)
13610      C$ = MID$(TN$,I,1)
13620      IF INSTR("0123456789ABCDEF",C$) = 0 THEN RETURN
13630      NEXT I
13640   'get value
13650    NUMVAL = VAL("&H" + TN$)
13660   'set type, return
13670    GOTO 13780
13680 '
13690 'decimal number?
13700   'scan for non-dec digits (exit)
13710    FOR I = 1 TO LEN(TN$)
13720      C$ = MID$(TN$,I,1)
13730      IF INSTR("0123456789-+",C$) = 0 THEN RETURN
13740      NEXT I
13750   'get value
13760    NUMVAL = VAL(TN$)
13770 '
13780 'sucess exit
13790  FOUND = TRUE
13800  IF LEN(HEX$(NUMVAL)) < 3  THEN NUMTYPE = IMMED16 OR IMMED8                        ELSE NUMTYPE = IMMED16
13810 RETURN
13820 '********************************************
13830 '* SUBROUTINE MEMREF                        *
13840 '* Trys to interpret target$ as a direct    *
13850 '* mem ref.  If sucessful, sets FOUND true, *
13860 '* & MEMADDR to the address referanced.     *
13870 '********************************************
13880 '
13890 MR$ = TARGET$  'save copy
13900 '
13910 'brackets?
13920  IF LEFT$(MR$,1) <> "[" OR RIGHT$(MR$,1) <> "]" THEN RETURN
13930 '
13940 'strip off brackets
13950  TARGET$ = MID$(MR$,2,LEN(MR$)-2)
13960 'try to interpret as addr.
13970   'might be number
13980    GOSUB 13440   'test_number
13990    IF NOT FOUND THEN 14030
14000      MEMADDR = NUMVAL
14010      GOTO 14150 'exit
14020 '
14030   'or might be symbol
14040    GOSUB 12030  'operand_lookup
14050    IF NOT FOUND THEN 14100
14060      IF (SYMTYPE(TABLEPTR) AND IMMED16) = FALSE THEN 14100
14070        MEMADDR = VAL1(TABLEPTR)
14080        GOTO 14150 'exit
14090 '
14100 'failure exit
14110  FOUND = FALSE
14120  TARGET$ = MR$
14130  RETURN
14140 '
14150 'sucessful exit
14160  TARGET$ = MR$
14170  RETURN
14180 '*****************************************************
14190 '* SUBROUTINE PARSE_DISP_OFF_REG                     *
14200 '* Trys to parse TARGET$ as an offset off a register *
14210 '* If sucessful, sets FOUND true, sets NEEDOFFSET    *
14220 '* to the offset's type, and OFFSET to it's value .  *
14230 '*****************************************************
14240 '
14250 PDOR$ = TARGET$  'save copy
14260 '
14270 'special case
14280  IF TARGET$ = "[BP]" THEN REGVAL = 6: NEEDOFFSET = IMMED8: OFFSET = 0:              GOTO 14670
14290 '
14300 'parse reg spec.
14310  'set ptr to candidate
14320   PTR = INSTR(TARGET$,"[")
14330   IF PTR <= 1 THEN 14710  'no disp, exit
14340  'isolate candidate
14350   REG$ = RIGHT$(PDOR$,LEN(PDOR$)-PTR+1)
14360  'valid reg. spec?
14370   IF REG$ = "[BP]" THEN REGVAL = 6: GOTO 14440
14380   TARGET$ = REG$
14390   GOSUB 12030  'operand_lookup
14400   IF NOT FOUND OR SYMTYPE(TABLEPTR) <> MEMREG THEN 14710
14410    'save reg value
14420     REGVAL = VAL1(TABLEPTR)
14430 '
14440 'now parse disp.
14450  'isolate candidate
14460   DISP$ = LEFT$(PDOR$,PTR-1)
14470  'valid disp?
14480   TARGET$ = DISP$
14490    'might be symbol
14500     GOSUB 12030   'operand_lookup
14510     IF NOT FOUND THEN 14560   'not sym
14520     IF (SYMTYPE(TABLEPTR) AND (IMMED16 OR IMMED8)) = FALSE THEN 14560
14530       NEEDOFFSET = SYMTYPE(TABLEPTR)
14540       OFFSET = VAL1(TABLEPTR)
14550       GOTO 14670
14560    'or number
14570     GOSUB 13440   'test_number
14580     IF NOT FOUND THEN 14620
14590       NEEDOFFSET = NUMTYPE
14600       OFFSET = NUMVAL
14610           GOTO 14670
14620    'or offset
14630     GOSUB 14750 'offset
14640     IF NOT FOUND THEN 14710
14650       NEEDOFFSET = OFFSETYPE
14660       OFFSET = OFFSETVAL
14670 'sucess exit
14680  TARGET$ = PDOR$
14690  FOUND = TRUE
14700  RETURN
14710 'failure exit
14720  TARGET$ = PDOR$
14730  FOUND = FALSE
14740  RETURN
14750 '***************************************************
14760 '* SUBROUTINE OFFSET                               *
14770 '* Trys to interpret TARGET$ as an offset operand. *
14780 '* If sucessful, set FOUND, set OFFSETYPE          *
14790 '* immed16, and TARGVAL1 to the label's offset.    *
14800 '***************************************************
14810 '
14820 OS$ = TARGET$
14830 '
14840 IF LEFT$(OS$,7) <> "OFFSET(" THEN FOUND = FALSE: RETURN
14850 IF PASS = 1 THEN 15010
14860 '
14870 'isolate label
14880   TARGET$ = MID$(TARGET$,8,LEN(TARGET$)-8)
14890 '
14900 'look it up
14910   GOSUB 12030 'operand_lookup
14920 '
14930 IF FOUND AND (SYMTYPE(TABLEPTR) AND (MEM OR NEAR)) THEN 14990
14940   ERRS = ERRS + 1
14950   PRINT#2, "****Error: Illegal or undefined argument for Offset"
14960   OFFSETVAL = 0
14970   GOTO 15010
14980 '
14990 OFFSETVAL = VAL1(TABLEPTR)
15000 '
15010 FOUND = TRUE
15020 OFFSETYPE = IMMED16
15030 TARGET$ = OS$
15040 RETURN
15050 '***************************************
15060 '* SUBROUTINE CHAR                     *
15070 '* Trys to interpret TARGET$ as a char *
15080 '***************************************
15090 FOUND = FALSE
15100 IF LEN(TARGET$) <> 3 THEN RETURN
15110 IF LEFT$(TARGET$,1) <> "'" THEN RETURN
15120 IF RIGHT$(TARGET$,1) <> "'" THEN RETURN
15130    FOUND = TRUE
15140    CHARVAL = ASC(MID$(TARGET$,2,1))
15150 RETURN
15160 '*************************************
15170 '* SUBROUTINE MACHOP                 *
15180 '* Updates loctr based on op length. *
15190 '* On pass 2, generates obj. code.   *
15200 '*************************************
15210 '
15220 GOSUB 15800  'op_type
15230 '
15240 'opcode
15250  LOCTR = LOCTR + 1
15260  IF PASS = 2 THEN GOSUB 16060  'build_opcode
15270 '
15280 '2nd op byte?
15290  IF (OPVAL(OPPTR) <> &HD5) AND (OPVAL(OPPTR) <> &HD4) THEN 15330
15300    LOCTR = LOCTR + 1
15310    IF PASS = 2 THEN OBJLEN = OBJLEN + 1: OBJ(OBJLEN) = &HA
15320 '
15330 'room for m. byte disp. (must go here, modebyte modifys offset)
15340  IF NEEDOFFSET = NONE THEN 15370
15350    IF (NEEDOFFSET AND IMMED8) THEN LOCTR = LOCTR + 1                                  ELSE LOCTR = LOCTR + 2
15360 '
15370 'if direct addr. mode byte, leave room for address
15380  IF (FLAG AND (NEEDMODEBYTE OR NEEDEXT)) = FALSE THEN 15410
15390    IF (DTYPE OR STYPE) AND MEM THEN LOCTR = LOCTR + 2
15400 '
15410 'extension byte?
15420  IF (FLAG AND NEEDEXT) = FALSE THEN 15460
15430    LOCTR = LOCTR + 1
15440    IF PASS = 2 THEN GOSUB 16320   'build_ext
15450 '
15460 'mode byte?
15470  IF (FLAG AND NEEDMODEBYTE) = FALSE THEN 15510
15480    LOCTR = LOCTR + 1
15490    IF PASS = 2 THEN GOSUB 16460  'build_modebyte
15500 '
15510 '8 bit disp.?
15520  IF (FLAG AND NEEDISP8) = FALSE THEN 15560
15530    LOCTR = LOCTR + 1
15540    IF PASS = 2 THEN GOSUB 16990  'build_disp8
15550 '
15560 '16 bit disp.?
15570  IF (FLAG AND NEEDISP16) = FALSE THEN 15610
15580    LOCTR = LOCTR + 2
15590    IF PASS = 2 THEN GOSUB 17210 'build_disp16
15600 '
15610 'immediate byte?
15620  IF (FLAG AND NEEDIMMED8) = FALSE THEN 15650
15630    LOCTR = LOCTR + 1
15640    IF PASS = 2 THEN GOSUB 17570
15650  IF WORD OR ((FLAG AND NEEDIMMED) = FALSE) THEN 15690
15660    LOCTR = LOCTR + 1
15670    IF PASS = 2 THEN GOSUB 17570   'build_immed8
15680 '
15690 'immediate word(s)?
15700  IF NOT(WORD) OR ((FLAG AND NEEDIMMED) = FALSE) THEN 15740
15710    IF DTYPE = IMMED16 THEN LOCTR = LOCTR + 4 ELSE LOCTR = LOCTR + 2
15720    IF PASS = 2 THEN GOSUB 17430  'build_immed16
15730 '
15740 'mem. addr.?
15750  IF (FLAG AND NEEDMEM) = FALSE THEN 15790
15760    LOCTR = LOCTR + 2
15770    IF PASS = 2 THEN GOSUB 17730  'mem_addr
15780 '
15790 RETURN
15800 '************************************
15810 '* SUBROUTINE OP_TYPE               *
15820 '* Decides between word & byte ops. *
15830 '************************************
15840 '
15850 IF (DTYPE OR STYPE) AND (REG16 OR ACUM16 OR SEG OR CS) THEN 15900
15860 IF (DTYPE OR STYPE) AND (REG8 OR ACUM8) THEN 15940
15870 '
15880 IF RIGHT$(OP$,1) = "B" THEN 15940
15890 '
15900 'word
15910  WORD = TRUE
15920  RETURN
15930 '
15940 'byte
15950  WORD = FALSE
15960  RETURN
15970 '**********************************************
15980 '* SUBROUTINE PSEUDO-OP                       *
15990 '* Branches to routines to handle each pseudo *
16000 '* op using the value field as an index.      *
16010 '**********************************************
16020 '
16030 ON OPVAL(OPPTR) GOSUB 17860, 18050, 18130, 18510, 18740, 18890
16040 '                      EQU    ORG    DB     DS     PROC   ENDP
16050 RETURN
16060 '**********************************************************
16070 '* SUBROUTINE BUILD_OPCODE                                *
16080 '* Builds opcode, stores it in obj. Increments objlength. *
16090 '**********************************************************
16100 '
16110 OBJLEN = OBJLEN + 1
16120 OBJ(OBJLEN) = OPVAL(OPPTR)
16130 '
16140 'add reg. field if requested
16150  IF (FLAG AND ADDREG) = FALSE THEN 16230
16160    'segment reg.
16170     IF DTYPE AND (SEG OR CS) THEN R = DVAL2: GOTO 16210
16180    'normal reg.
16190     IF (FLAG AND DIRECTION) THEN R = SVAL2/8 ELSE R = DVAL2/8
16200 '
16210    OBJ(OBJLEN) = OBJ(OBJLEN) + R
16220 '
16230 'auto word bit?
16240  IF (FLAG AND AUTOW) = FALSE THEN 16270
16250    IF WORD THEN OBJ(OBJLEN) = OBJ(OBJLEN) + 1
16260 '
16270 'auto count bit?
16280  IF (FLAG AND AUTOC) = FALSE THEN 16310
16290    IF STYPE AND CL THEN OBJ(OBJLEN) = OBJ(OBJLEN) + 2
16300 '
16310 RETURN
16320 '**************************************************
16330 '* SUBROUTINE BUILD_EXTENSION_BYTE                *
16340 '* Builds an opcode extension byte.  The ext. val *
16350 '* is extracted from bits 3-5 of the flag word.   *
16360 '**************************************************
16370 '
16380 'get ext.
16390  MASK = &H38
16400  EXT = FLAG AND MASK
16410 '
16420 'define proper operand as ext. & build mode byte
16430   IF FLAG AND DIRECTION THEN DVAL2 = EXT ELSE SVAL2 = EXT
16440   GOSUB 16460  'build_modebyte
16450 RETURN
16460 '***************************************************************
16470 '* SUBROUTINE BUILD_MODE_BYTE                                  *
16480 '* Given direction flag, memreg values in dval1 and sval1 and  *
16490 '* reg values in dval2 and sval2, builds an addressing mode    *
16500 '* byte.  If necessary, also builds displacement byte(s).      *
16510 '***************************************************************
16520 '
16530 OBJLEN = OBJLEN + 1
16540 '
16550 'special case: direct mem. addressing?
16560  IF ((DTYPE OR STYPE) AND MEM) = FALSE THEN 16630
16570    IF DTYPE = MEM THEN  M = SVAL2 ELSE M = DVAL2
16580      OBJ(OBJLEN) = 6 + M
16590      GOSUB 17730  'build_mem_addr
16600      RETURN
16610 '
16620 'normal mode byte
16630  'operands in normal or reverse order?
16640   IF FLAG AND DIRECTION THEN M = SVAL1 + DVAL2 ELSE M = DVAL1 + SVAL2
16650 '
16660  OBJ(OBJLEN) = M
16670 '
16680 'offset byte(s)?
16690 '
16700 IF NEEDOFFSET = NONE THEN 16880
16710 '
16720 '8 bit disp.
16730 IF OFFSET > 127 OR OFFSET < -128 THEN 16810
16740   OBJ(OBJLEN) = OBJ(OBJLEN) + 64  'set mod field
16750   'crunch neg. offset to 8 bits
16760     IF OFFSET < 0 THEN OFFSET = OFFSET AND &HFF
16770   OBJLEN = OBJLEN + 1
16780   OBJ(OBJLEN) = OFFSET
16790   RETURN
16800 '
16810 '16 bit disp.
16820  OBJ(OBJLEN) = OBJ(OBJLEN) + 128  'set mod field
16830  OBJLEN = OBJLEN + 2
16840  'convert to hi/low form
16850     NUMLOW = OFFSET: GOSUB 16890  'hi/low
16860  OBJ(OBJLEN-1) = NUMLOW
16870  OBJ(OBJLEN) = NUMHIGH
16880 RETURN
16890 '************************************************
16900 '* SUBROUTINE HI/LOW                            *
16910 '* Splits 16 bit number in numlow, into two     *
16920 '* byte-sized componants in numhigh and numlow. *
16930 '************************************************
16940 H$ = HEX$(NUMLOW)
16950 H$ = STRING$(4-LEN(H$),"0") + H$
16960 NUMLOW =  VAL("&H" + RIGHT$(H$,2))
16970 NUMHIGH = VAL("&H" + LEFT$(H$,2))
16980 RETURN
16990 '*********************************************
17000 '* SUBROUTINE BUILD_DISP8                    *
17010 '* Calculates the disp. from the present     *
17020 '* loc to the loc given as an operand.       *
17030 '* Prints error message if disp. exceeds 127.*
17040 '*********************************************
17050 '
17060 'calculate disp.
17070  D = DVAL1 - LOCTR
17080 '
17090 'check size
17100  IF ABS(D) < 128 THEN 17140
17110    D = 0
17120    IF PASS = 2 THEN PRINT#2,"****Error: Too far for short jump":                     ERRS = ERRS + 1
17130 '
17140 'if neg. crunch to 8 bits
17150  IF D < 0 THEN D = D AND &HFF
17160 '
17170 'build obj. code
17180  OBJLEN = OBJLEN + 1
17190  OBJ(OBJLEN) = D
17200 RETURN
17210 '********************************************
17220 '* SUBROUTINE BUILD_DISP16                  *
17230 '* Builds 16 bit displacement. Prints error *
17240 '* msg. for negative disps not on CALL ops. *
17250 '********************************************
17260 '
17270 'calculate disp.
17280  D = DVAL1 - LOCTR
17290 '
17300 IF OP$ = "JMP" AND D<=128 THEN PRINT#2, "****Diagnostic: Could use JMPS" :        DIAG = DIAG + 1
17310 '
17320 'legal?
17330  IF D >= 0 OR OP$ = "CALL" THEN 17370
17340    D = 0
17350    IF PASS = 2 THEN PRINT#2,"****Error: Illegal reverse long jump":                  ERRS = ERRS + 1
17360 '
17370 'build obj. code
17380  NUMLOW = D: GOSUB 16890  'hi/low
17390  OBJLEN = OBJLEN + 2
17400  OBJ(OBJLEN-1) = NUMLOW
17410  OBJ(OBJLEN) = NUMHIGH
17420 RETURN
17430 '************************************
17440 '* SUBROUTINE BUILD_IMMED16         *
17450 '* Builds word(s) of immediate data *
17460 '************************************
17470 '
17480 IF DTYPE AND IMMED16 THEN IVAL = DVAL1: GOSUB 17510
17490 IF STYPE AND IMMED16 THEN IVAL = SVAL1: GOSUB 17510
17500 RETURN
17510 'internal subroutine immed16
17520 NUMLOW = IVAL: GOSUB 16890   'hi/low
17530 OBJLEN = OBJLEN + 2
17540 OBJ(OBJLEN-1) = NUMLOW
17550 OBJ(OBJLEN) = NUMHIGH
17560 RETURN
17570 '**********************************
17580 '* SUBROUTINE BUILD_IMMED8        *
17590 '* Builds byte of immediate data. *
17600 '**********************************
17610 '
17620 IF DTYPE AND IMMED8 THEN IVAL = DVAL1: GOSUB 17650
17630 IF STYPE AND IMMED8 THEN IVAL = SVAL1: GOSUB 17650
17640 RETURN
17650 'int. sub. immed8
17660 IF IVAL <= 255 AND IVAL >= 0 THEN 17700
17670   IVAL = 0
17680   IF PASS = 2 THEN ERRS = ERRS + 1: PRINT#2,"****Error: Data too long"
17690 '
17700 OBJLEN = OBJLEN + 1
17710 OBJ(OBJLEN) = IVAL
17720 RETURN
17730 '*********************************
17740 '* SUBROUTINE MEMREF             *
17750 '* Builds a memory address word. *
17760 '*********************************
17770 '
17780 'get addr. in hi/low form
17790  IF DTYPE = MEM THEN NUMLOW = DVAL1 ELSE NUMLOW = SVAL1
17800  GOSUB 16890
17810 'build word
17820  OBJLEN = OBJLEN + 2
17830  OBJ(OBJLEN-1) = NUMLOW
17840  OBJ(OBJLEN) = NUMHIGH
17850 RETURN
17860 '***************************
17870 '* SUBROUTINE EQU          *
17880 '* Handles equ pseudo-op.  *
17890 '***************************
17900 '
17910 IF (LABEL$ <> "")  THEN 17950
17920   IF PASS = 2 THEN ERRS = ERRS+1: PRINT#2,"****Error: EQU without symbol"
17930   RETURN
17940 '
17950 IF PASS = 2 THEN 18040
17960 '
17970 IF DTYPE <> (NEAR OR MEM) THEN 18020   'pass 1 default if not found
17980   ERRS = ERRS + 1
17990   PRINT#2, "****Error: EQU with forward referance in ";LINENUM
18000   RETURN
18010 '
18020 VAL1(NUMSYM) = DVAL1
18030 SYMTYPE(NUMSYM) = DTYPE
18040 RETURN
18050 '**************************
18060 '* SUBROUTINE ORG         *
18070 '* Handles org pseudo-op. *
18080 '**************************
18090 '
18100 'set loctr to new value
18110  LOCTR = DVAL1
18120 RETURN
18130 '*************************
18140 '* SUBROUTINE DB         *
18150 '* Handles db pseudo-op. *
18160 '*************************
18170 '
18175 IF PASS = 2 THEN 18210
18180 'label? set type to mem
18190  IF LABEL$ <> "" THEN SYMTYPE(NUMSYM) = MEM
18200 '
18210 'scan operand area, building obj. code
18220  LINEPTR = OPDPTR: LINEPTR2 = OPDPTR
18230  WHILE LINEPTR < ENDPTR
18240   'get operand
18250    GOSUB 11270  'get_field
18260    IF NOT FOUND THEN 18380  'exit
18270   'branch for byte value or string
18280    TARGET$ = FLD$: GOSUB 13440 'test_number
18290    IF NOT FOUND OR (NUMTYPE AND IMMED8) = FALSE THEN 18320
18300      GOSUB 18400  'build_byte
18310      GOTO 18370
18320    IF LEFT$(FLD$,1) <> "'" THEN 18350
18330      GOSUB 18440  'build_stg
18340      GOTO 18370
18350   'if not byte or string, error on pass 2
18360    IF PASS = 2 THEN PRINT#2,"****Error: unrecognized operand ";FLD$:                 ERRS = ERRS + 1
18370   WEND
18380 LOCTR = LOCTR + OBJLEN
18390 RETURN
18400 'subroutine build_byte
18410 OBJLEN = OBJLEN + 1
18420 OBJ(OBJLEN) = NUMVAL
18430 RETURN
18440 'subroutine build_stg
18450 FLD$ = MID$(FLD$,2,LEN(FLD$)-2) 'strip off 's
18460 FOR I = 1 TO LEN(FLD$)
18470   OBJLEN = OBJLEN + 1
18480   OBJ(OBJLEN) = ASC(MID$(FLD$,I,1))
18490   NEXT I
18500 RETURN
18510 '*************************
18520 '* SUBROUTINE DS         *
18530 '* Handles ds pseudo-op. *
18540 '*************************
18550 '
18560 DSFLAG = TRUE  'signal this is a ds
18565 IF PASS = 2 THEN 18610 'skip type setting second time
18570 '
18580 'label? set type to mem
18590  IF LABEL$ <> "" THEN SYMTYPE(NUMSYM) = MEM
18600 '
18610 'set output code
18620  IF STYPE AND IMMED8 THEN DSVAL = SVAL1 ELSE DSVAL = 0
18630 '
18640 'on pass 2, generate obj. code directly
18650  IF PASS = 1 THEN 18700
18660    FOR I = 1 TO DVAL1
18670      LSET BYTE$ = CHR$(DSVAL): PUT #3
18680      NEXT I
18690 '
18700 'advance loctr, update bytesgen
18710  LOCTR = LOCTR + DVAL1: BYTESGEN = BYTESGEN + DVAL1
18720 '
18730 RETURN
18740 '***************************
18750 '* SUBROUTINE PROC         *
18760 '* Handles proc pseudo-op. *
18770 '***************************
18780 '
18790 IF STKTOP < MAXSTK THEN 18850
18800   IF PASS = 1 THEN 18830
18810     ERRS = ERRS + 1
18820     PRINT#2, "****Error: Procedures nested too deeply"
18830   RETURN
18840 '
18850 'push new proc type for returns
18860  STKTOP = STKTOP + 1
18870  PROCTYPE(STKTOP) = DTYPE
18880 RETURN
18890 '********************
18900 '* SUBROUTINE ENDP  *
18910 '* Pops proc stack. *
18920 '********************
18930 '
18940 IF STKTOP > 0 THEN 19000
18950   IF PASS = 1 THEN 18980
18960     ERRS = ERRS + 1
18970     PRINT#2, "****Error: ENDP without PROC"
18980   RETURN
18990 '
19000 STKTOP = STKTOP - 1
19010 RETURN
19020 '************************************
19030 '* SUBROUTINE OUTPUT                *
19040 '* Outputs obj code & listing line, *
19050 '* given code in obj(objlength).    *
19060 '************************************
19070 '
19075 'update number of bytes generated
19076  BYTESGEN = BYTESGEN + OBJLEN
19080 IF DSFLAG THEN H$ = HEX$(LOCTR-DVAL1) ELSE H$ = HEX$(LOCTR-OBJLEN)
19090 H$ = STRING$(4-LEN(H$),"0") + H$
19100 PRINT#2, TAB(1) H$;
19110 'first 6 bytes
19120  I = 1
19130  PRINT#2, TAB(6)
19140  WHILE I <= 6
19150    IF I > OBJLEN THEN 19220
19160    LSET BYTE$ = CHR$(OBJ(I)): PUT #3
19170    H$ = HEX$(OBJ(I)): IF LEN(H$) = 1 THEN H$ = "0" + H$
19180    PRINT#2, H$;
19190    I = I + 1
19200    WEND
19210 '
19220 'source (truncate if necessary)
19230  PRINT#2, TAB(19)
19240  PRINT#2, USING "####"; LINENUM;
19250  PRINT#2, SPACE$(2) LEFT$(INPLINE$, LWIDTH-26)
19260 '
19270 'rest of obj. code
19280  WHILE I <= OBJLEN
19290    IF I MOD 6 = 1 THEN PRINT#2, TAB(6)
19300    LSET BYTE$ = CHR$(OBJ(I)): PUT #3
19310    H$ = HEX$(OBJ(I)): IF LEN(H$) = 1 THEN H$ = "0" + H$
19320    PRINT#2, H$;
19330    I = I + 1
19340    WEND
19350 IF OBJLEN > 6 THEN PRINT#2,
19360 RETURN
19370 '***************************
19380 '* SUBROUTINE PASSTWO_INIT *
19390 '***************************
19400 '
19410 'reset input file
19420  CLOSE #1: OPEN SC$ FOR INPUT AS #1
19430 '
19440 PASS = 2
19450 LOCTR = 256
19460 LINENUM = 0
19465 BYTESGEN = 0
19470 '
19480 RETURN
19490 '************************
19500 '* SUBROUTINE FINALPROC *
19510 '* Cleanup              *
19520 '************************
19530 '
19540 IF STKTOP > 0 THEN ERRS = ERRS + 1: PRINT#2,"****Error: missing ENDP"
19550 '
19560 PRINT#2,: PRINT#2,: PRINT#2, ERRS; "Error(s) detected"
19570 PRINT#2, DIAG; "Diagnostic(s) offered"
19575 PRINT#2,: PRINT#2, BYTESGEN; "Bytes of object code generated"
19580 'dump sym table
19590  GOSUB 19690
19600 'return printer to normal
19610  IF L$ = "lpt1:" THEN PRINT#2, PMODEOFF$
19620 'hang onto screen listing
19630  IF L$ <> "scrn:" THEN 19680
19640    PRINT: BEEP: COLOR 0,7
19650    PRINT TAB(30) "Hit any key to exit" TAB(79);
19660    C$ = INKEY$: IF C$ = "" THEN 19660
19670    COLOR 7,0
19680 RETURN
19690 '*****************************
19700 '* SUBROUTINE DUMP_SYM_TABLE *
19710 '*****************************
19720 '
19730 PRINT#2,: PRINT#2, "SYMBOL TABLE DUMP:"
19740 I = PREDEF + 1
19750 F$ =  "\        \!\  \\  \"  'format
19760 PERLINE = LWIDTH \ LEN(F$)
19770 WHILE I <= NUMSYM
19780   H$ = HEX$(VAL1(I)): H$ = STRING$(4-LEN(H$),"0") + H$
19790   PRINT#2, USING F$; SYM$(I); " ";  H$; "    ";
19800   I = I + 1
19810   IF (I-PREDEF) MOD PERLINE = 1 THEN PRINT#2,
19820   WEND
19830 PRINT#2,
19840 RETURN
19850 '*************************************
19860 '* SUBROUTINE PROGESS REPORT         *
19870 '* Maintains reassuring msg. on scrn *
19880 '*************************************
19890 '
19900 X = POS(0): Y = CSRLIN: LOCATE 25,1: COLOR 0,7: PRINT TAB(20);
19910 IF PASS = 1 THEN PRINT "First"; ELSE PRINT "Second";
19920 PRINT " pass in progress. Lines processed = "; LINENUM;
19930 PRINT TAB(79);: COLOR 7,0: LOCATE Y,X
19940 RETURN
19950 '****************************************
19960 '* SUBROUTINE SET_UP_SYMBOL_TABLE       *
19970 '* Sets up sym table, & opens obj. file *
19980 '****************************************
19990 '
20000 INPUT#3, PREDEF, MAXSYM: LINE INPUT#3, C$: LINE INPUT#3, C$
20010 DIM SYM$(MAXSYM), VAL1(MAXSYM), VAL2(PREDEF), SYMTYPE(MAXSYM)
20020 '
20030 FOR I = 1 TO PREDEF  '# of pre-defined syms
20040   INPUT#3, SYM$(I), VAL1(I), VAL2(I), SYMTYPE(I)
20050   NEXT I
20060 NUMSYM = PREDEF
20070 '
20080 CLOSE #3
20090 OPEN O$ AS #3 LEN=1: FIELD #3,1 AS BYTE$
20100 RETURN
50000 '**********************************
50010 '* SUBROUTINE INIT                *
50020 '* Initializes all but sym table. *
50030 '**********************************
50040 '
50050 DEFINT A-Z
50060 ERRS = 0: DIAG = 0
50070 '
50080 'title page
50090  GOSUB 50190
50100 'define constants
50110  GOSUB 50450
50120 'open files
50130  GOSUB 50660
50140 'op table
50150  GOSUB 51190
50160 'listing header
50170  GOSUB 51350
50180 RETURN
50190 '*************************************************
50200 '* SUBROUTINE TITLE                              *
50210 '* Prints title page, & waits for user response. *
50220 '*************************************************
50230 '
50240 SCREEN 0,0,0: WIDTH 80: KEY OFF: CLS: LOCATE 24,1,0
50250 PRINT TAB(12)"?";STRING$(56,"?");"?
50260 PRINT TAB(12)"?"TAB(69)"?
50270 PRINT TAB(12)"?"TAB(32)"CHASM  version 2.01"TAB(69)"?
50280 PRINT TAB(12)"?"TAB(69)"?
50290 PRINT TAB(12)"?"TAB(25)"Cheap Assembler for the IBM PC"TAB(69)"?
50300 PRINT TAB(12)"?"TAB(69)"?
50310 PRINT TAB(12)"?      If you have used this program and found it of     ?
50320 PRINT TAB(12)"?   value, your $20 contribution will be appreciated.    ?
50330 PRINT TAB(12)"?"TAB(69)"?
50340 PRINT TAB(12)"?"TAB(29)"David Whitman"TAB(69)"?
50350 PRINT TAB(12)"?"TAB(29)"2 North Park Street"TAB(69)"?
50360 PRINT TAB(12)"?"TAB(29)"Apartment L"TAB(69)"?
50370 PRINT TAB(12)"?"TAB(29)"Hanover, NH  03755"TAB(69)"?
50380 PRINT TAB(12)"?"TAB(69)"?
50390 PRINT TAB(12)"?   You are encouraged to copy and share this program.   ?
50400 PRINT TAB(12)"?"TAB(69)"?
50410 PRINT TAB(12) "?";STRING$(56,"?");"?":PRINT
50420 PRINT TAB(27) "Hit any key to continue...":PRINT:PRINT
50430 I$ = INKEY$: IF I$ = "" THEN 50430
50440 CLS: RETURN
50450 '****************************
50460 '* SUBROUTINE SET_CONSTANTS *
50470 '****************************
50480 'general
50490  TRUE = -1: FALSE = 0: DELIM$ = " ," + CHR$(9)
50500 '
50510 'flag values
50520 'bits 3-5 reserved for ext. values
50530  MACHOP = 1: AUTOW = 4: ADDREG = 64: NEEDEXT = 128
50540  NEEDISP8 = 256: NEEDISP16 = 512: NEEDMODEBYTE = 1024: NEEDIMMED8 = 2048
50550  NEEDIMMED = 4096: DIRECTION = 8192: NEEDMEM = 16384: AUTOC = &H8000
50560 '
50570 'operand types
50580  ACUM8 = 1: ACUM16 = 2: REG8 = 4: REG16 = 8: MEMREG = 16: CS = 32
50590  SEG = 64: MEM = 128: IMMED8 = 256: IMMED16 = 512: NONE = 1024
50600  STRING = 2048: NEAR = 4096: FAR = 8192: CL = 16384
50610 '
50620 'arrays
50630 MAXOBJ = 50: DIM OBJ(MAXOBJ)
50640 MAXSTK = 10: DIM PROCTYPE(MAXSTK): STKTOP = 0
50650 RETURN
50660 '*****************************************************
50670 '* SUBROUTINE OPEN_FILES                             *
50680 '* Prompts user for i/o filenames, then opens files. *
50690 '*****************************************************
50700 '
50710 ON ERROR GOTO 51000
50720 '
50730 'input file
50740  LOCATE 1,1: INPUT"Source code file name? [.asm] ", S$
50750  IF S$ = "" THEN BEEP: GOTO 50740
50760  'if no extension, add default
50770     IF INSTR(S$,".") = 0                                                              THEN SC$ = S$ + ".asm"                                                          ELSE SC$ = S$: S$ = LEFT$(S$,INSTR(S$,".")-1)
50780    OPEN SC$ FOR INPUT AS #1
50790  LOCATE 3,1
50800  INPUT"Direct listing to Printer (P), Screen (S), or Disk (D)?",L$
50810  IF L$ = "" THEN BEEP: GOTO 50790
50820    IF INSTR("PpSsDd",L$) = 0 THEN BEEP: GOTO 50790  'invalid response
50830    IF L$ = "P" OR L$ = "p" THEN L$ = "lpt1:" : GOTO 50890  'printer?
50840    IF L$ = "S" OR L$ = "s" THEN L$ = "scrn:" : GOTO 50890  'screen?
50850      LOCATE 3,1: PRINT SPACE$(79);: LOCATE 3,1
50860      PRINT"Name for listing file? [";S$;".lst] ";
50870      INPUT "",L$
50880      IF L$ = "" THEN L$ = S$ + ".lst"  'default to source name
50890    OPEN L$ FOR OUTPUT AS #2
50900 PRINT#2, 'test listing device
50910 'object file
50920  LOCATE 5,1: PRINT "Name for object file?  [";S$;".com] ";
50930  INPUT "",O$
50940  'default to source file name.com
50950    IF O$ = "" THEN O$ = S$ + ".com"
50960  'will open after symtable setup
50970 ON ERROR GOTO 0 'kill error trapping
50980  PRINT: PRINT: PRINT
50990 RETURN
51000 '****************
51010 '*Error Handler *
51020 '****************
51030 '
51040 IF ERR = 53 THEN 51050
51045 IF NOT((ERR = 52) AND (ERL = 50780)) THEN 51120
51050   COLOR 0,7: BEEP
51060   PRINT SC$; " not found.  Press Esc to exit, anything else to continue.";
51070   SC$ = INKEY$: IF SC$ = "" THEN 51070
51080   IF SC$ = CHR$(27) THEN SYSTEM
51090   LOCATE ,1: COLOR 7,0: PRINT SPACE$(80);
51100   LOCATE 1,31: PRINT SPACE$(48); : LOCATE ,1: RESUME 50740
51110 '
51120 IF ERR <> 27 THEN 51180
51130    CLOSE #2: COLOR 0,7: BEEP
51140    PRINT"Printer not available.  Press any key to continue.";
51150    L$ = INKEY$ : IF L$ = "" THEN 51150
51160    LOCATE ,1: COLOR 7,0: PRINT SPACE$(79);
51170    LOCATE 3,56: PRINT SPACE$(23);: LOCATE ,1: RESUME 50800
51180 ON ERROR GOTO 0
51190 '***********************
51200 '* SUBROUTINE OP_TABLE *
51210 '***********************
51220 '
51221 'put reassuring message on screen
51222  X = POS(0): Y = CSRLIN: LOCATE 25,1: COLOR 16,7
51223  PRINT TAB(30) "*Set-up in progress*" TAB(79);
51224  COLOR 7,0: LOCATE Y,X
51225 '
51230 OPEN "chasm.dat" FOR INPUT AS #3
51240 'note: c$ used to skip data comments
51250 '
51260 INPUT#3, NUMOP: LINE INPUT#3,C$: LINE INPUT#3, C$
51270 DIM OPCODE$(NUMOP), OPVAL(NUMOP), SRCTYPE(NUMOP)
51280 DIM DSTTYPE(NUMOP), OFLAG(NUMOP)
51290 '
51300 FOR I = 1 TO NUMOP
51310   INPUT#3, OPCODE$(I),OPVAL(I),DSTTYPE(I),SRCTYPE(I),OFLAG(I)
51320   LINE INPUT#3, C$
51330   NEXT I
51340 RETURN
51350 '*************************
51360 '* SUBROUTINE HEADER     *
51370 '* Prints listing header.*
51380 '*************************
51390 '
51400 LWIDTH = 79  'default width
51410 '
51420 'title & date
51430  D$ = LEFT$(DATE$,2) + "/" + MID$(DATE$,4,2) + "/" +  RIGHT$(DATE$,2)
51440  PRINT#2, SC$ TAB(LWIDTH-LEN(D$)) D$:PRINT#2,:PRINT#2,
51450 '
51460 'printer set up?
51470  IF L$ <> "lpt1:" THEN 51540
51480    'for NEC 8023 printer, remove quotes for auto condensed mode
51490    'similar code may be substituted for other printers.
51500   LWIDTH = 131: WIDTH #2, LWIDTH + 1
51510   PRINT#2, CHR$(27) + "Q" 'pmodeon
51520   PMODEOFF$ = CHR$(27) + "N"
51530 '
51540 'column headings
51550  PRINT#2,"LOC"TAB(6)"OBJ"TAB(19)"LINE"TAB(25)"SOURCE":PRINT#2,
51560 '
51570 RETURN