1359 lines
56 KiB
NASM
1359 lines
56 KiB
NASM
; =====> SRCH_STR.ASM
|
||
;***************************************
|
||
;* TIPC Scheme Runtime Support *
|
||
;* String Search Capabilities *
|
||
;* *
|
||
;* (C) Copyright 1985 by Texas *
|
||
;* Instruments Incorporated. *
|
||
;* All rights reserved. *
|
||
;* *
|
||
;* Date Written: 21 July 1985 *
|
||
;* Last Modification: 17 October 1985 *
|
||
;***************************************
|
||
include scheme.equ
|
||
include pcmake.equ
|
||
include sinterp.arg
|
||
IFDEF PROMEM
|
||
include rpc.equ
|
||
include xli_pro.mac
|
||
include realio.equ
|
||
.286c
|
||
ENDIF
|
||
|
||
DGROUP group data
|
||
XGROUP group PROGX
|
||
PGROUP group prog
|
||
|
||
MSDOS equ 021h
|
||
TI_CRT equ 049h
|
||
IBM_CRT equ 010h
|
||
|
||
; Definitions for control characters
|
||
CTL_A equ 1
|
||
CTL_I equ 9
|
||
CTL_Z equ 26
|
||
|
||
data segment word public 'DATA'
|
||
assume DS:DGROUP
|
||
IFDEF PROMEM
|
||
;from pro2real.asm
|
||
extrn REAL_BUF_SELECTOR:word,REAL_BUF_TOP:word,RPC_HANDLE:byte
|
||
ENDIF
|
||
ret_sav1 dw 0 ; return address save area
|
||
ret_sav2 dw 0 ; return address save area
|
||
m_srch_f db "SUBSTRING-FIND-NEXT-CHAR-IN-SET",0
|
||
m_srch_b db "SUBSTRING-FIND-PREVIOUS-CHAR-IN-SET",0
|
||
m_st_ln db "STRING-LENGTH",0
|
||
m_mk_str db "MAKE-STRING",0
|
||
m_stapnd db "%STRING-APPEND",0
|
||
m_reifs db "%REIFY-STACK",0
|
||
m_reifsb db "%REIFY-STACK!",0
|
||
m_st_dsp db "%SUBSTRING-DISPLAY",0
|
||
m_opnd dw INVALID_OPERAND_ERROR ; numeric error code
|
||
m_one dw 1 ; a constant "one" (1)
|
||
data ends
|
||
|
||
prog segment byte public 'PROG'
|
||
assume CS:PGROUP
|
||
extrn %allocbl:far ; "alloc_block" linkage routine
|
||
extrn next:far ; Interpreter's "next instruction" point
|
||
extrn next_PC:far ; Interpreter's "next instruction" point
|
||
extrn sch_err:far ; Linkage to Scheme debugger
|
||
;************************************************************************
|
||
;* Far Linkage to "set_src_err" *
|
||
;************************************************************************
|
||
public %set_src
|
||
%set_src proc far
|
||
pop ret_sav1
|
||
pop ret_sav2
|
||
push DS ; make ES point to the current data segment
|
||
pop ES
|
||
extrn set_src_:near
|
||
call set_src_
|
||
push ret_sav2
|
||
push ret_sav1
|
||
ret
|
||
%set_src endp
|
||
|
||
;************************************************************************
|
||
;* Far Linkage to "set_numeric_error" *
|
||
;************************************************************************
|
||
public %set_num
|
||
%set_num proc far
|
||
pop ret_sav1
|
||
pop ret_sav2
|
||
push DS ; make ES point to the current data segment
|
||
pop ES
|
||
extrn set_nume:near
|
||
call set_nume
|
||
push ret_sav2
|
||
push ret_sav1
|
||
ret
|
||
%set_num endp
|
||
|
||
;************************************************************************
|
||
;* Far Linkage to "dissamble" *
|
||
;************************************************************************
|
||
public %disasse
|
||
%disasse proc far
|
||
pop ret_sav1
|
||
pop ret_sav2
|
||
push DS ; make ES point to the current data segment
|
||
pop ES
|
||
extrn disassem:near
|
||
call disassem
|
||
push ret_sav2
|
||
push ret_sav1
|
||
ret
|
||
%disasse endp
|
||
|
||
;************************************************************************
|
||
;* Far Linkage to "get_port" *
|
||
;************************************************************************
|
||
public %getport
|
||
%getport proc far
|
||
pop ret_sav1
|
||
pop ret_sav2
|
||
push DS ; make ES point to the current data segment
|
||
pop ES
|
||
extrn get_port:near
|
||
call get_port
|
||
push ret_sav2
|
||
push ret_sav1
|
||
ret
|
||
%getport endp
|
||
|
||
prog ends
|
||
|
||
PROGX segment byte public 'PROGX'
|
||
assume CS:XGROUP
|
||
|
||
extrn CRT_DSR:far
|
||
|
||
;************************************************************************
|
||
;* Substring-Find-Next-Char-in-Set *
|
||
;************************************************************************
|
||
srch_arg struc
|
||
strt_off dw ? ; starting offset (16 bit positive integer)
|
||
end_off dw ? ; ending offset (16 bit positive integer)
|
||
lngth dw ? ; number of characters in source string
|
||
result dw ? ; index of character matched
|
||
|
||
; Note: the following two entries are order dependent
|
||
str_beg dw ? ; beginning offset of string
|
||
str_DS dw ? ; segment register value for string
|
||
|
||
srch_BP dw ? ; caller's BP
|
||
dw ? ; caller's ES
|
||
dd ? ; return address (far)
|
||
dw ? ; return address (near)
|
||
str_reg dw ? ; register containing string
|
||
strt_reg dw ? ; register containing substr starting offset
|
||
end_reg dw ? ; register containing substr ending offset
|
||
cs_reg dw ? ; register containing charset string
|
||
srch_arg ends
|
||
|
||
srch_str proc far
|
||
|
||
%srchprv label far
|
||
mov CX,1 ; set search direction = backward
|
||
jmp short srch_go ; go to common processing code
|
||
|
||
; Long Branch to Source Error Support
|
||
srch_er1: jmp srch_err
|
||
|
||
%srchnxt label far
|
||
xor CX,CX ; set search direction = forward
|
||
|
||
srch_go: push ES ; save caller's ES register
|
||
push BP ; save caller's BP register
|
||
sub SP,offset srch_BP ; allocate local storage
|
||
mov BP,SP ; establish addressability of local data
|
||
|
||
; Validate Source String Argument
|
||
mov BX,[BP].str_reg ; load address of string register
|
||
mov SI,[BX].C_page ; and load string's page number
|
||
cmp byte ptr ptype+[SI],STRTYPE*2 ; is source string a string?
|
||
jne srch_er1 ; if not a string, error (jump)
|
||
%LoadPage ES,SI
|
||
;;; mov ES,pagetabl+[SI] ; load string's paragraph address
|
||
mov SI,[BX].C_disp ; load displacement of string
|
||
mov AX,ES:[SI].str_len ; load length of string
|
||
cmp AX,0 ;;; check length of string
|
||
jge srch_01
|
||
add AX,PTRSIZE
|
||
jmp srch_02
|
||
srch_01: sub AX,BLK_OVHD ; and compute number of characters in it
|
||
srch_02: mov [BP].lngth,AX ; save string length for further testing
|
||
add SI,BLK_OVHD ; advance string start to first character
|
||
mov [BP].str_beg,SI ; save starting character offset
|
||
mov [BP].str_DS,ES ; and segment register pointer
|
||
|
||
; Validate Starting Offset Argument
|
||
mov BX,[BP].strt_reg ; load address of starting offset regsiter
|
||
call get_num ; obtain the integer value
|
||
jc srch_er1 ; if carry set, error
|
||
mov [BP].strt_off,AX ; and save it for future use
|
||
|
||
; Validate Ending Offset Argument
|
||
mov BX,[BP].end_reg ; load address of ending offset register
|
||
call get_num ; obtain the integer value
|
||
jc srch_er1 ; if carry set, error
|
||
cmp [BP].strt_off,AX ; is starting offset greater than ending?
|
||
ja srch_er1 ; if so, invalid substring range (jump)
|
||
cmp AX,[BP].lngth ; test ending offset against string length
|
||
ja srch_er1 ; if ending offset too big, error (jump)
|
||
mov [BP].end_off,AX ; save ending offset for future use
|
||
|
||
; Validate Charset String Argument
|
||
mov BX,[BP].cs_reg ; load number of register holding charset
|
||
mov DI,[BX].C_page ; load page number of charset pointer
|
||
cmp byte ptr ptype+[DI],STRTYPE*2 ; this is a sting, isn't it?
|
||
jne char_p ; if not a string, error (jump)
|
||
%LoadPage ES,DI
|
||
;;; mov ES,pagetabl+[DI] ; load paragraph address of string
|
||
mov DI,[BX].C_disp ; load displacement of string in page
|
||
mov DX,ES:[DI].str_len ; load length of string object
|
||
cmp DX,0 ;;; check length of string
|
||
jge srch_03
|
||
add DX,PTRSIZE
|
||
jmp srch_04
|
||
srch_03: sub DX,BLK_OVHD ; compute number of characters in charset
|
||
srch_04: add DI,BLK_OVHD ; advance string pointer past block header
|
||
jmp short go
|
||
char_p: cmp DI,SPECCHAR*2 ; is charset argument a single character?
|
||
je char_p0 ; Yes, continue
|
||
jmp srch_er1 ; No, error (jump)
|
||
|
||
; Single character search-- optimize it
|
||
char_p0: mov AL,byte ptr [BX].C_disp
|
||
les DI,dword ptr [BP].str_beg
|
||
mov DX,CX ; save direction indicator in DX
|
||
mov CX,[BP].end_off ; compute length of search string
|
||
sub CX,[BP].strt_off
|
||
je not_fnd1 ; if search length is zero, return 'nil
|
||
cmp DX,0
|
||
jne b_ward ; if backward, jump
|
||
; search for single character in forward direction
|
||
add DI,[BP].strt_off ; compute address of start of substring
|
||
repne scasb ; search for single character
|
||
jne not_fnd1 ; character found? If so, jump
|
||
dec DI ; fix up ending index
|
||
jmp short over
|
||
; search for single character in backward direction
|
||
b_ward: add DI,[BP].end_off ; compute address of end of substring
|
||
dec DI
|
||
std ; set search direction to be backwards
|
||
repne scasb ; search for single character
|
||
cld ; reset "direction" flag to go forwards
|
||
jne not_fnd1 ; if search length is zero, return 'nil
|
||
inc DI ; fix up ending index
|
||
over: mov SI,DI ; copy character address to SI
|
||
sub SI,[BP].str_beg ; and compute found character's address
|
||
jmp short found ; return index to found character
|
||
|
||
; Determine whether string search is forward or backward
|
||
go: push DS ; save the data segment address
|
||
cmp CX,0 ; in which direction are we to search?
|
||
je forward ; if CX=0, forward; else backward
|
||
|
||
; Register Usage in Innermost Loop:
|
||
; DS:SI - pointer to next character in source string
|
||
; ES:DI - pointer to charset string
|
||
; AL - search character
|
||
; BX - ending offset (source string)
|
||
; CX - length of charset string
|
||
; DX - length of charset string (used to refresh CX)
|
||
|
||
; Search Source String in a Backwards Direction
|
||
mov BX,[BP].str_beg ; compute ending offset for string
|
||
add BX,[BP].strt_off
|
||
lds SI,dword ptr [BP].str_beg ; load addr of string's beginning
|
||
add SI,SS:[BP].end_off ; and compute end of substring address
|
||
jmp short startb ; jump to initial entry point in loop
|
||
|
||
loopb: sub DI,DX ; reset starting offset of charset string
|
||
startb: cmp SI,BX ; at beginning of substring?
|
||
jbe not_fnd ; if at end, jump
|
||
mov CX,DX ; reload charset string length
|
||
dec SI ; decrement source string index
|
||
mov AL,[SI] ; and load next character to test
|
||
repne scasb ; search charset for current character
|
||
jne loopb
|
||
pop DS ; restore DS to point to data segment
|
||
sub SI,[BP].str_beg ; compute index of current character
|
||
jmp short found ; current character found in charset
|
||
|
||
; no characters found which appear in the charset
|
||
not_fnd: pop DS ; restore DS to current data segment
|
||
not_fnd1: xor AX,AX ; store #!false in the
|
||
mov BX,[BP].str_reg ; destination register
|
||
mov byte ptr [BX].C_page,AL
|
||
mov [BX].C_disp,AX
|
||
jmp short ret ; return to caller
|
||
|
||
; Search Source String in a Forward Direction
|
||
forward: mov BX,[BP].str_beg ; compute ending offset for string
|
||
add BX,[BP].end_off
|
||
lds SI,dword ptr [BP].str_beg ; load addr of string's beginning
|
||
add SI,SS:[BP].strt_off ; and compute beginning of substring
|
||
jmp short start ; jump to initial entry point in loop
|
||
|
||
loop: sub DI,DX ; reset starting offset of charset string
|
||
start: cmp SI,BX ; at end of source string?
|
||
jae not_fnd ; if at end, jump
|
||
mov CX,DX ; reload charset string length
|
||
lodsb ; load next character to test
|
||
repne scasb ; search charset for current character
|
||
jne loop
|
||
|
||
; current character found in charset-- return offset of current character
|
||
pop DS ; restore DS to current data segment
|
||
sub SI,[BP].str_beg ; adjust offset of character found
|
||
dec SI
|
||
found: mov BX,[BP].str_reg ; load address of destination register
|
||
call ret_num ; convert offset to Scheme integer
|
||
|
||
; return to caller
|
||
ret: xor AX,AX ; set completion code for normal return
|
||
ret1: add SP,offset srch_BP ; release local storage
|
||
pop BP ; restore the caller's BP register
|
||
pop ES ; restore the caller's ES register
|
||
ret ; return
|
||
|
||
; error-- invalid operand to string search primitive
|
||
srch_err: pushm <[BP].cs_reg,[BP].end_reg,[BP].strt_reg,[BP].str_reg>
|
||
cmp CX,0 ; search forward or backward?
|
||
jne backward ; if backward search, jump
|
||
mov AX,offset m_srch_f
|
||
jmp short common
|
||
backward: mov AX,offset m_srch_b
|
||
common: mov BX,4 ; load VM argument count
|
||
pushm <BX,AX> ; push args=4, name of instruction
|
||
call %set_src ; call set_src_err(...);
|
||
mov AX,-1 ; load "invalid operand" flag
|
||
mov SP,BP ; drop arguments off the TIPC's stack
|
||
jmp ret1 ; return to interpreter
|
||
|
||
srch_str endp
|
||
|
||
dumy_arg struc
|
||
dw ? ; caller's BP
|
||
dd ? ; return address (far linkage)
|
||
dw ? ; return address (near linkage)
|
||
arg1 dw ? ; register address for argument 1
|
||
arg2 dw ? ; register address for argument 2
|
||
arg3 dw ? ; register address for argument 3
|
||
arg4 dw ? ; register address for argument 4
|
||
dumy_arg ends
|
||
|
||
;************************************************************************
|
||
;* AL *
|
||
;* (string-length string) string-length d=s1 *
|
||
;* *
|
||
;* Purpose: Scheme Interpreter support for the "string-lengt" function.*
|
||
;************************************************************************
|
||
%st_len proc far
|
||
push BP ; save the caller's BP register
|
||
mov BP,SP ; establish addressability for arguments
|
||
; validate the string argument
|
||
mov BX,[BP].arg1 ; load address of argument register
|
||
mov SI,[BX].C_page ; load the string's page number
|
||
cmp byte ptr ptype+[SI],STRTYPE*2 ; it is a string, isn't it?
|
||
jne st_l_err ; if not a string, error (jump)
|
||
; compute string length
|
||
%LoadPage ES,SI
|
||
;;; mov ES,pagetabl+[SI] ; load paragraph address of string's page
|
||
mov SI,[BX].C_disp ; load string's displacement
|
||
mov SI,ES:[SI].str_len ; load length field from string object
|
||
cmp SI,0 ;;; check length of string
|
||
jge str_010
|
||
add SI,PTRSIZE
|
||
jmp str_020
|
||
str_010: sub SI,BLK_OVHD ; and compute number of characters in it
|
||
; return string length as an integer
|
||
str_020: call ret_num ; create Scheme representation for integer
|
||
; return
|
||
xor AX,AX ; set error code for normal return
|
||
str_ret: pop BP ; restore the caller's BP register
|
||
ret ; return to caller
|
||
; ***error-- operand was not a string***
|
||
st_l_err: mov AX,offset m_st_ln ; load text address for "STRING-LENGTH"
|
||
mov CX,1 ; indicate one operand
|
||
pushm <BX,CX,AX> ; push arguments for call
|
||
call %set_src ; call: set_src_err("STRING-LENGTH",1,arg1)
|
||
mov SP,BP ; drop arguments off stack
|
||
mov AX,-1 ; indicate error return
|
||
jmp str_ret ; return
|
||
%st_len endp
|
||
|
||
;************************************************************************
|
||
;* MAKE-STRING (MAKE-STRING LENGTH INIT-VAL) *
|
||
;* *
|
||
;* Purpose: Scheme Interpreter support for the "MAKE-STRING" function. *
|
||
;* *
|
||
;* Note: The maximum length of a PCS string is 2^16 - 3 (65,532) *
|
||
;* characters. *
|
||
;************************************************************************
|
||
%makestr proc far
|
||
push BP ; save the caller's BP register
|
||
mov BP,SP ; establish addressability for arguments
|
||
; validate the length operand
|
||
mov BX,[BP].arg1 ; load address of reg containing length
|
||
call get_num ; get the value of the integer
|
||
jc mk_s_err ; error? if so, jump
|
||
; allocate the string object
|
||
mov CX,STRTYPE ; load the type code for a string
|
||
pushm <AX,CX,BX> ; push arguments for the call
|
||
call %allocbl ; call: alloc_block(arg1, STRTYPE, length)
|
||
mov SP,BP ; drop the arguments off the stack
|
||
; validate the initialization value
|
||
mov BX,[BP].arg2 ; load address of register with init value
|
||
mov SI,[BX].C_page ; load initialization value's page number
|
||
cmp SI,0 ; default initialization value (nil)?
|
||
jne mk_s_ch ; if not nil, check for character (jump)
|
||
mov AL," " ; use blank (" ") as default fill value
|
||
jmp short mk_s_in ; initialize the string
|
||
mk_s_ch: cmp SI,SPECCHAR*2 ; is initialization value a character?
|
||
jne mk_s_err ; if not a character or nil, error (jump)
|
||
mov AL,byte ptr [BX].C_disp ; load the value of the character
|
||
; initialize the string
|
||
mk_s_in: mov BX,[BP].arg1 ; load a pointer to the newly allocated
|
||
mov DI,[BX].C_disp
|
||
mov BX,[BX].C_page
|
||
%LoadPage ES,BX
|
||
;;; mov ES,pagetabl+[BX]
|
||
mov CX,[BP].arg3 ; load length of string object
|
||
add DI,BLK_OVHD ; advance string ptr to 1st char position
|
||
rep stosb ; propagate initval throughout string
|
||
; return to caller
|
||
xor AX,AX ; set the return code for a normal return
|
||
mk_s_ret: pop BP ; restore the caller's BP register
|
||
ret ; return
|
||
; ***error-- invalid operand to MAKE-STRING***
|
||
mk_s_err: mov AX,offset m_mk_str ; load addr of "MAKE-STRING" text
|
||
mov BX,2 ; load argument count = 2
|
||
pushm <[BP].arg2,[BP].arg1,BX,AX>
|
||
call %set_src ; set_src_err("MAKE-STRING",2,arg1,arg2)
|
||
mov SP,BP ; drop arguments off TIPC stack
|
||
mov AX,-1 ; indicate error return
|
||
jmp short mk_s_ret ; return
|
||
%makestr endp
|
||
|
||
;************************************************************************
|
||
;* (%str-append str1 start1 end1 {nil,char,str2} str3 start3 end3) *
|
||
;************************************************************************
|
||
str_arg struc
|
||
start1 dw ? ; starting offset of first string
|
||
start3 dw ? ; starting offset of third string
|
||
len1 dw ? ; length of first string
|
||
len2 dw ? ; length of second string
|
||
len3 dw ? ; length of third string
|
||
str_BP dw ? ; caller's BP
|
||
dw ? ; caller's SI
|
||
dw ? ; caller's ES
|
||
reg7 dw ? ; address of 7th operand register
|
||
reg6 dw ? ; address of 6th operand register
|
||
reg5 dw ? ; address of 5th operand register
|
||
reg4 dw ? ; address of 4th operand register
|
||
reg3 dw ? ; address of 3rd operand register
|
||
reg2 dw ? ; address of 2nd operand register
|
||
reg_1 dw ? ; address of 1st operand register
|
||
str_arg ends
|
||
|
||
public str_apnd
|
||
%strapnd proc far
|
||
str_err1: jmp str_err ; indirect jump to error code
|
||
; Load operands of this here instruction and compute register addresses
|
||
str_apnd: mov CX,7 ; load count of number of operands
|
||
str_ld: xor AX,AX ; clear AH
|
||
lods byte ptr ES:[SI] ; load register number of this operand
|
||
add AX,offset reg0 ; and compute the register's address
|
||
push AX ; save the register's address on the stack
|
||
loop str_ld ; continue until all operands processed
|
||
; Save registers and establish addressability of local storage
|
||
push ES ; save caller's ES register
|
||
push SI ; save caller's SI register
|
||
push BP ; save caller's BP register
|
||
sub SP,offset str_BP ; allocate local storage
|
||
mov BP,SP ; and establish addressability
|
||
|
||
; Validate the First String's Starting Offset
|
||
mov BX,[BP].reg2 ; load address of start1 register
|
||
call get_num ; fetch value for start1
|
||
jc str_err1 ; if error, jump
|
||
add AX,BLK_OVHD ; advance starting offset past block header
|
||
mov [BP].start1,AX ; save start1 offset
|
||
; Validate the First String's Ending Offset
|
||
mov BX,[BP].reg3 ; load address of end1 register
|
||
call get_num ; fetch value for end1
|
||
jc str_err1 ; if error, jump
|
||
add AX,BLK_OVHD ; advance ending offset past block header
|
||
; Validate the First String Operand
|
||
mov BX,[BP].reg_1 ; load address of string1 register
|
||
mov SI,[BX].C_page ; load string's page number
|
||
cmp byte ptr ptype+[SI],STRTYPE*2 ; it is a string, isn't it?
|
||
jne str_err1 ; if not a string, error (jump)
|
||
%LoadPage ES,SI
|
||
;;; mov ES,pagetabl+[SI] ; load a pointer to the string
|
||
mov SI,[BX].C_disp
|
||
mov CX,ES:[SI].str_len ; ending offset past string end?
|
||
cmp CX,0 ;;; check length of string
|
||
jge str_01
|
||
add CX,BLK_OVHD+PTRSIZE ;;; adjust the string length
|
||
str_01: cmp AX,CX
|
||
ja str_err1 ; if ending offset too big, error (jump)
|
||
sub AX,[BP].start1 ; is ending offset too small?
|
||
jb str_err1 ; if ending offset smaller than start, jump
|
||
mov [BP].len1,AX ; save length of substring1
|
||
|
||
; Validate the Third String's Starting Offset
|
||
mov BX,[BP].reg6 ; load address of start3 register
|
||
call get_num ; fetch value for start3
|
||
jc str_err ; if error, jump
|
||
add AX,BLK_OVHD ; advance starting offset past block header
|
||
mov [BP].start3,AX ; save start3 offset
|
||
; Validate the Third String's Ending Offset
|
||
mov BX,[BP].reg7 ; load address of end3 register
|
||
call get_num ; fetch value for end3
|
||
jc str_err ; if error, jump
|
||
add AX,BLK_OVHD ; advance ending offset past block header
|
||
; Validate the Third String Operand
|
||
mov BX,[BP].reg5 ; load address of string3 register
|
||
mov SI,[BX].C_page ; load string's page number
|
||
cmp byte ptr ptype+[SI],STRTYPE*2 ; it is a string, isn't it?
|
||
jne str_err ; if not a string, error (jump)
|
||
%LoadPage ES,SI
|
||
;;; mov ES,pagetabl+[SI] ; load a pointer to the string
|
||
mov SI,[BX].C_disp
|
||
mov CX,ES:[SI].str_len ; ending offset past string end?
|
||
cmp CX,0 ;;; check length of string
|
||
jge str_02
|
||
add CX,BLK_OVHD+PTRSIZE ;;; adjust the string length
|
||
str_02: cmp AX,CX
|
||
ja str_err ; if ending offset too big, error (jump)
|
||
sub AX,[BP].start3 ; is ending offset too small?
|
||
jb str_err ; if ending offset smaller than start, jump
|
||
mov [BP].len3,AX ; save length of substring3
|
||
|
||
; Validate the "thing" to be inserted between string1 and string3
|
||
mov BX,[BP].reg4 ; load register with said "thing"
|
||
mov SI,[BX].C_page ; load page number
|
||
cmp SI,NIL_PAGE*2 ; is object nil?
|
||
jne str_10 ; if not nil, jump
|
||
; The "thing" is nil-- indicate nothing to insert
|
||
mov [BP].len2,0 ; indicate zero length "thing"
|
||
jmp short str_30 ; continue processing
|
||
|
||
; ***We interrupt this routine for some error support code***
|
||
str_err: mov AX,offset m_stapnd
|
||
mov CX,7
|
||
pushm <[BP].reg7,[BP].reg6,[BP].reg5,[BP].reg4,[BP].reg3>
|
||
pushm <[BP].reg2,[BP].reg_1,CX,AX>
|
||
call %set_src
|
||
mov SP,BP
|
||
add SP,offset str_BP
|
||
pop BP
|
||
pop SI
|
||
pop ES
|
||
jmp sch_err
|
||
|
||
str_10: cmp SI,SPECCHAR*2 ; is "thing" a character?
|
||
jne str_20 ; if not a character, jump
|
||
; The "thing" is a character
|
||
mov [BP].len2,1 ; indicate length = 1 character
|
||
jmp short str_30
|
||
str_20: cmp byte ptr ptype+[SI],STRTYPE*2 ; is "thing" a string?
|
||
jne str_err ; if not a string, error (jump)
|
||
; The "thing" is a string-- establish string length
|
||
%LoadPage ES,SI
|
||
;;; mov ES,pagetabl+[SI] ; load string page's paragraph address
|
||
mov SI,[BX].C_disp
|
||
mov AX,ES:[SI].str_len
|
||
cmp AX,0 ;;; check length of string
|
||
jge str_03
|
||
add AX,PTRSIZE
|
||
jmp str_04
|
||
str_03: sub AX,BLK_OVHD ; and compute number of characters in it
|
||
str_04: mov [BP].len2,AX ; save string length for further testing
|
||
|
||
; All arguments OK, allocate the new string
|
||
str_30: mov AX,[BP].len1 ; compute the length of the new string
|
||
add AX,[BP].len2
|
||
add AX,[BP].len3
|
||
cmp AX,16383 ; is new string greater than max string size?
|
||
jg str_err ; Yes ... error
|
||
mov BX,STRTYPE ; load tag=string
|
||
mov CX,offset tmp_reg
|
||
pushm <AX,BX,CX> ; push arguments to call
|
||
call %allocbl
|
||
mov SP,BP ; drop arguments off the stack
|
||
mov DI,tmp_page ; load pointer to newly allocated string
|
||
%LoadPage0 ES,DI
|
||
;;; mov ES,pagetabl+[DI]
|
||
mov DI,tmp_disp ; pointer is now in ES:[DI]
|
||
add DI,BLK_OVHD ; advance pointer to 1st character location
|
||
; Move in data from all substrings
|
||
mov CX,[BP].len1 ; load length of string1
|
||
mov BX,[BP].reg_1 ; load addr of register containing string 1
|
||
mov SI,[BX].C_disp ; load string 1's offset
|
||
add SI,[BP].start1 ; add in offset of starting character
|
||
mov BX,[BX].C_page ; load page number
|
||
push DS ; save the data segment register
|
||
%LoadPage1 DS,BX
|
||
;;; mov DS,pagetabl+[BX]
|
||
;**********************************************************************
|
||
;* * * Warning: The data segment register (DS) does not point to * * *
|
||
;* * * the data segment in the code which follows * * *
|
||
;**********************************************************************
|
||
rep movsb ; copy string1 into new string
|
||
pop DS ; restore data segment register
|
||
|
||
mov CX,[BP].len2 ; load length of string2
|
||
cmp CX,0 ; any characters to move?
|
||
je str_60 ; if no characters, jump
|
||
mov BX,[BP].reg4 ; load addr of register with "thing"
|
||
mov SI,SS:[BX].C_disp ; load a pointer to "thing"
|
||
mov BX,SS:[BX].C_page
|
||
push DS ; Save data segment register
|
||
cmp BL,SPECCHAR*2 ; is "thing" a character?
|
||
jne str_40 ; if not a character, then a string (jump)
|
||
mov SI,[BP].reg4 ; load addr of register containing character
|
||
jmp short str_50
|
||
str_40: %LoadPage1 DS,BX
|
||
;;; mov DS,SS:pagetabl+[BX] ; "thing" is a string-- load pointer
|
||
add SI,BLK_OVHD ; to it and advance to 1st character
|
||
str_50:
|
||
rep movsb ; copy string2 into new string
|
||
pop DS ; restore data segment register
|
||
|
||
str_60: mov CX,[BP].len3 ; load length of string3
|
||
mov BX,[BP].reg5 ; load addr of register containing string 3
|
||
mov SI,SS:[BX].C_disp ; load string offset
|
||
add SI,[BP].start3 ; advance starting offset past block header
|
||
mov BX,SS:[BX].C_page ; load the string's page number and
|
||
push DS
|
||
%LoadPage1 DS,BX
|
||
;;; mov DS,SS:pagetabl+[BX] ; paragraph address
|
||
rep movsb ; copy string3 into new string
|
||
pop DS ; restore the data segment register
|
||
;**********************************************************************
|
||
;* * * Warning: The data segment register (DS) does not point to * * *
|
||
;* * * the data segment in the code above * * *
|
||
;**********************************************************************
|
||
|
||
; Place pointer to new string into the destination register
|
||
mov DI,[BP].reg_1 ; load destination register address
|
||
mov AL,byte ptr tmp_page
|
||
mov byte ptr [DI].C_page,AL
|
||
mov AX,tmp_disp
|
||
mov [DI].C_disp,AX
|
||
|
||
; Return
|
||
add SP,offset str_BP ; deallocate local storage
|
||
pop BP ; restore caller's BP
|
||
pop SI ; restore caller's SI
|
||
pop ES ; restore caller's ES
|
||
jmp next ; return to Scheme interpreter
|
||
|
||
%strapnd endp
|
||
|
||
;************************************************************************
|
||
;* Reify(!)-Stack *
|
||
;* *
|
||
;* Purpose: To provide the ability to manipulate items on the Scheme *
|
||
;* runtime stack from Scheme. *
|
||
;* *
|
||
;* Description: The elements of the stack are referenced by providing *
|
||
;* the byte offset of the desired element as an index *
|
||
;* to the REIFY-STACK or REIFY-STACK! instruction. An *
|
||
;* index of -1 to REIFY-STACK is a request that the current*
|
||
;* stack frame pointer be returned. *
|
||
;************************************************************************
|
||
r_stk struc
|
||
bang dw ? ; fetch/store indicator
|
||
r_stk_BP dw ? ; caller's BP
|
||
dd ? ; return address (far call)
|
||
dw ? ; return address (near call)
|
||
r_index dw ? ; register containing index; destination reg
|
||
r_value dw ? ; register containing value (for stores)
|
||
r_stk ends
|
||
|
||
%reifyst proc far
|
||
; ***Error-- Invalid Index for REIFY-STACK(!) Instruction***
|
||
reif_err: cmp CX,0 ; is this a fetch or store?
|
||
jne reif_e10 ; if store, jump
|
||
mov AX,offset m_reifs ; load text address for "REIFY-STACK"
|
||
mov BX,1 ; indicate 1 operand to this instruction
|
||
jmp short reif_e20 ; jump to common error code
|
||
reif_e10: mov AX,offset m_reifsb ; load text address for "REIFY-STACK!"
|
||
mov BX,2 ; indicate 2 operands to this instruction
|
||
push [BP].r_value ; and push second reigster operand
|
||
reif_e20: pushm <[BP].r_index,BX,AX> ; push arguments
|
||
call %set_src ; indicate source operand error
|
||
mov SP,BP ; drop arguments off the stack
|
||
mov AX,-1 ; load an error flag
|
||
jmp reif_rt1 ; return with error flag in AX
|
||
|
||
; (REIFY-STACK! index value) ; entry point
|
||
%reifstb label far
|
||
mov CX,1 ; indicate a store operation
|
||
jmp short reif_go ; jump to common entry code
|
||
|
||
; (REIFY-STACK index) ; entry point
|
||
%reifstk label far
|
||
xor CX,CX ; indicate a fetch operation
|
||
|
||
reif_go: push BP ; save the caller's BP register
|
||
sub SP,offset r_stk_BP ; allocate local storage
|
||
mov BP,SP ; establish addressability for operands/data
|
||
|
||
; Validate index
|
||
mov BX,[BP].r_index ; load address of register containing index
|
||
cmp CX,0 ; is this a REIFY-STACK operation?
|
||
jne reif_no ; if not, skip special check for -1
|
||
; Check for an index of -1 indicating we need to return FP
|
||
cmp byte ptr [BX].C_page,SPECFIX*2 ; is index a fixnum?
|
||
jne reif_no ; if not a fixnum index, jump
|
||
cmp [BX].C_disp,07FFFh ; is index a -1?
|
||
jne reif_no ; if not -1, jump
|
||
mov AX,FP ; load FP's offset in stack buffer
|
||
add AX,BASE ; and add BASE to compute absolute offset
|
||
mov SI,AX ; copy quotient to SI
|
||
call ret_num ; convert element index to a Scheme integer
|
||
jmp reif_ret ; return the element index of FP
|
||
; Fetch the index value
|
||
reif_no: call get_num ; fetch the integer value
|
||
jc reif_err ; if not a valid index, jump
|
||
push AX ; save the byte offset
|
||
xor DX,DX ; convert to a double word (w/out sign ext)
|
||
mov BX,PTRSIZE ; load divisor
|
||
div BX ; divide by number of bytes/pointer
|
||
pop AX ; restore the byte index
|
||
cmp DX,0 ; is remainder zero?
|
||
jne reif_err ; if not a multiple of PTRSIZE, error (jump)
|
||
mov DX,BASE ; compute the current top of stack (TOS)
|
||
add DX,TOS ; offset
|
||
cmp AX,DX ; is index larger than TOS?
|
||
ja reif_err ; if so, error (jump)
|
||
|
||
; Attempt to find the desired element in the stack buffer
|
||
cmp AX,BASE ; is BASE < element index?
|
||
jb reif_cnt ; if so, element is in previous stack segment
|
||
sub AX,BASE ; compute byte offset of desired element
|
||
add AX,offset S_stack ; compute offset in stack buffer
|
||
mov SI,AX ; and move offset into SI
|
||
mov AX,DS ; put data segment address into ES so that
|
||
mov ES,AX ; desired element is pointed to by ES:[SI]
|
||
jmp reif_do ; fetch/store the element
|
||
|
||
; Find the element in a previous stack segment (a continuation object)
|
||
reif_cnt: mov BX,PREV_pag ; make ES:[SI] point to the previous
|
||
mov SI,PREV_dis ; stack segment continuation object
|
||
%LoadPage ES,BX
|
||
;;; mov ES,pagetabl+[BX]
|
||
; Follow stack segment chain until desired offset found
|
||
reif_lop: cmp AX,ES:[SI].con_base ; compare element index:continuation base
|
||
jae reif_fnd ; if offset > base, element in this segment
|
||
mov BL,ES:[SI].con_spag ; load pointer to previous stack segment
|
||
mov SI,ES:[SI].con_sdis ; into ES:[SI]
|
||
%LoadPage ES,BX
|
||
;;; mov ES,pagetabl+[BX] ;
|
||
jmp short reif_lop ; loop until desired segment found
|
||
; Element found in stack segment (continuation) object
|
||
reif_fnd: sub AX,ES:[SI].con_base ; subtrace off continuation's base
|
||
add SI,AX ; add entry's byte offset
|
||
add SI,offset con_data ; adjust for continuation header
|
||
|
||
; Desired stack element address by ES:[SI]-- is this a fetch or store?
|
||
reif_do: cmp CX,0 ; test fetch/store flag
|
||
jne reif_st ; if a store, jump
|
||
; Fetch desired stack element
|
||
mov BX,[BP].r_index ; load address of destination register
|
||
mov AL,ES:[SI].car_page ; load page number of stack entry
|
||
mov byte ptr [BX].C_page,AL ; and store into destination register
|
||
mov AX,ES:[SI].car ; load displacement of stack entry
|
||
mov [BX].C_disp,AX ; and store into destination register
|
||
jmp short reif_ret
|
||
; Re-define desired stack element
|
||
reif_st: mov BX,[BP].r_value ; load add of register containing new value
|
||
mov AL,byte ptr [BX].C_page
|
||
mov ES:[SI].car_page,AL
|
||
mov AX,[BX].C_disp
|
||
mov ES:[SI].car,AX
|
||
|
||
; return to caller
|
||
reif_ret: xor AX,AX ; indicate no error encountered
|
||
reif_rt1: add SP,offset r_stk_BP ; deallocate local storage
|
||
pop BP ; restore the caller's BP register
|
||
ret ; return to caller
|
||
%reifyst endp
|
||
|
||
;************************************************************************
|
||
;* AL AL AH AL AH *
|
||
;* (%SUBSTRING-DISPLAY string start end row-bias window) *
|
||
;* *
|
||
;* Purpose: Special support for displaying strings to the CRT for *
|
||
;* applications such as text editors. *
|
||
;************************************************************************
|
||
|
||
IFDEF PROMEM
|
||
|
||
SD_BSIZE equ 100 ; buffer size
|
||
sd_args struc
|
||
; Warning: the following five (5) items are order dependent
|
||
sd_dummy dw ? ; extra for realio
|
||
sd_len dw ? ; #chars in following buffer
|
||
sd_buff db SD_BSIZE dup (?) ; string buffer
|
||
sd_text dw ? ; text attributes for window
|
||
sd_cursv dw ? ; cursor coordinate save area
|
||
;
|
||
sd_char db ? ; "saved" character
|
||
sd_streg dw ? ; string register address
|
||
sd_start dw ? ; substring's starting offset
|
||
sd_end dw ? ; substring's ending offset
|
||
sd_bias dw ? ; row bias
|
||
sd_cline dw ? ; cursor line number
|
||
sd_ccol dw ? ; cursor column number
|
||
sd_nline dw ? ; number of lines in the window
|
||
sd_ncols dw ? ; number of columns in the window
|
||
sd_ullin dw ? ; upper left corner line number
|
||
sd_ulcol dw ? ; upper left corner column number
|
||
sd_arg45 dw ? ; arguments 4,5 save area
|
||
sd_last dw ? ; last write flag
|
||
sd_linum db ? ; line number
|
||
; Warning: the following two (2) items are order dependent
|
||
sd_wn_SI dw ? ; pointer to window object, part 1
|
||
sd_wn_ES dw ? ; pointer to window object, part 2
|
||
;
|
||
sd_BP dw ? ; caller's BP
|
||
sd_args ends
|
||
|
||
ELSE
|
||
|
||
sd_args struc
|
||
sd_buff db 100 dup (?) ; string buffer
|
||
sd_char db ? ; "saved" character
|
||
sd_streg dw ? ; string register address
|
||
sd_start dw ? ; substring's starting offset
|
||
sd_end dw ? ; substring's ending offset
|
||
sd_bias dw ? ; row bias
|
||
sd_cline dw ? ; cursor line number
|
||
sd_ccol dw ? ; cursor column number
|
||
sd_nline dw ? ; number of lines in the window
|
||
sd_ncols dw ? ; number of columns in the window
|
||
sd_ullin dw ? ; upper left corner line number
|
||
sd_ulcol dw ? ; upper left corner column number
|
||
sd_text dw ? ; text attributes for window
|
||
sd_arg45 dw ? ; arguments 4,5 save area
|
||
sd_cursv dw ? ; cursor coordinate save area
|
||
sd_last dw ? ; last write flag
|
||
sd_linum db ? ; line number
|
||
; Warning: the following two (2) items are order dependent
|
||
sd_wn_SI dw ? ; pointer to window object, part 1
|
||
sd_wn_ES dw ? ; pointer to window object, part 2
|
||
;
|
||
sd_BP dw ? ; caller's BP
|
||
sd_args ends
|
||
SD_BSIZE equ sd_char-sd_buff ; buffer size
|
||
|
||
ENDIF
|
||
public str_disp
|
||
strdisp proc far
|
||
sd_err1: jmp sd_err ; indirect branch to error code
|
||
|
||
; load all five (5) of this instruction's operands
|
||
str_disp: lods byte ptr ES:[SI]
|
||
add AX,offset reg0
|
||
mov BX,AX ; save address of string register
|
||
lods word ptr ES:[SI]
|
||
mov DX,AX
|
||
lods word ptr ES:[SI]
|
||
save <SI> ; save location pointer
|
||
|
||
; allocate local storage
|
||
push BP
|
||
sub SP,offset sd_BP
|
||
mov BP,SP
|
||
mov [BP].sd_last,0 ; initialize "last write?" flag
|
||
mov [BP].sd_linum,0 ; line number
|
||
|
||
; save off argument information
|
||
mov [BP].sd_streg,BX
|
||
mov [BP].sd_arg45,AX
|
||
|
||
; validate the string offsets
|
||
xor BX,BX ; clear register BX
|
||
mov BL,DL ; copy starting offset register number
|
||
add BX,offset reg0 ; and compute register's address
|
||
call get_num ; obtain starting offset
|
||
jc sd_err1 ; valid offset? if not, error (jump)
|
||
add AX,BLK_OVHD ; adjust offset for block header
|
||
mov [BP].sd_start,AX ; save starting offset
|
||
xor BX,BX
|
||
mov BL,DH ; copy ending offset register number
|
||
add BX,offset reg0 ; and compute register's address
|
||
call get_num ; obtain ending offset
|
||
jc sd_err1 ; valid offset? if not, error (jump)
|
||
add AX,BLK_OVHD ; adjust offset for block header
|
||
cmp AX,[BP].sd_start ; is ending offset greater than starting?
|
||
jb sd_err1 ; if ending offset smaller, error (jump)
|
||
mov [BP].sd_end,AX ; save ending offset
|
||
|
||
; validate the row-bias
|
||
xor BX,BX
|
||
mov BL,byte ptr [BP].sd_arg45
|
||
cmp byte ptr reg0_pag+[BX],SPECFIX*2
|
||
je next$0
|
||
jmp sd_err
|
||
next$0: mov AX,reg0_dis+[BX]
|
||
shl AX,1
|
||
sar AX,1
|
||
mov [BP].sd_bias,AX
|
||
|
||
; Validate the window operand
|
||
xor AX,AX
|
||
mov AL,byte ptr [BP].sd_arg45+1
|
||
add AX,offset reg0
|
||
pushm <m_one,AX> ; push mode=output, reg address
|
||
call %getport ; map port operand (result in tmp_reg)
|
||
cmp AX,0 ; valid port operand?
|
||
jne sd_err ; if not a port, error (jump)
|
||
mov SI,tmp_page ; load a pointer to the port object
|
||
%LoadPage ES,SI
|
||
;;; mov ES,pagetabl+[SI]
|
||
mov SI,tmp_disp
|
||
mov AX,ES:[SI].pt_pflgs ; load the port attributes
|
||
test AX,WINDOW ; is this port a window?
|
||
jz sd_err ; if not a window, error (jump)
|
||
test AX,OPEN ; window open for output?
|
||
jnz sd_open ; if open, jump
|
||
jmp sd_done ; if closed, ignore I/O request (jump)
|
||
; Move parameters from the window object to local storage
|
||
sd_open: mov AX,ES:[SI].pt_cline ; get cursor line number
|
||
mov [BP].sd_cline,AX
|
||
mov AX,ES:[SI].pt_ccol ; get cursor column number
|
||
mov [BP].sd_ccol,AX
|
||
mov AX,ES:[SI].pt_nline ; get number of lines in window
|
||
mov [BP].sd_nline,AX
|
||
mov AX,ES:[SI].pt_ncols ; get number of columns in window
|
||
mov [BP].sd_ncols,AX
|
||
mov AX,ES:[SI].pt_ullin ; get upper left corner's line number
|
||
mov [BP].sd_ullin,AX
|
||
mov AX,ES:[SI].pt_ulcol ; get upper left corner's column number
|
||
mov [BP].sd_ulcol,AX
|
||
mov AX,ES:[SI].pt_text ; get window's text attributes
|
||
mov [BP].sd_text,AX
|
||
mov [BP].sd_wn_ES,ES ; save pointer to window object
|
||
mov [BP].sd_wn_SI,SI
|
||
jmp short sd_more ; branch over error code
|
||
|
||
; ***error-- invalid operand***
|
||
sd_err: mov SP,BP ; clean up stack
|
||
add SP,offset sd_BP
|
||
pop BP
|
||
restore <SI> ; load address of next instruction and
|
||
sub SI,6 ; adjust for 5 operands + opcode
|
||
mov AX,offset m_st_dsp ; load address of "SUBSTRING-DISPLAY"
|
||
pushm <SI,AX> ; push arguments to "disassemble"
|
||
call %disasse ; create *irritant* (pointer in tmp_reg)
|
||
pushm <tmp_adr,m_opnd,m_one> ; push operands
|
||
call %set_num ; indicate source operand error
|
||
jmp sch_err ; Link to Scheme debugger
|
||
|
||
; validate the string operand
|
||
sd_more: mov BX,[BP].sd_streg ; load string register's address
|
||
mov SI,[BX].C_page ; load string's page number
|
||
cmp byte ptr ptype+[SI],STRTYPE*2 ; type = string?
|
||
jne sd_err ; if not a string, error (jump)
|
||
%LoadPage ES,SI
|
||
;;; mov ES,pagetabl+[SI] ; load pointer to string
|
||
mov SI,[BX].C_disp
|
||
mov AX,ES:[SI].str_len ; load string's length
|
||
cmp AX,0 ;;; check length of string
|
||
jge sd_010
|
||
add AX,BLK_OVHD+PTRSIZE ;;; adjust for small string
|
||
sd_010: cmp AX,[BP].sd_end ; is ending offset too big?
|
||
jb sd_err ; if too big, error (jump)
|
||
; Note: ES:[SI] points to the source string
|
||
mov DX,[BP].sd_end ; load ending displacement and
|
||
add DX,SI ; compute ending address
|
||
add SI,[BP].sd_start ; compute starting address
|
||
|
||
; translate the string into the local buffer
|
||
mov CX,[BP].sd_ccol ; load current cursor position
|
||
mov BX,[BP].sd_ncols ; load line length
|
||
mov DI,BP ; load pointer to local data
|
||
add DI,sd_buff ; and address buffer
|
||
push DS ; save the data segment register
|
||
mov AX,ES ; make DS point to the page containing
|
||
mov DS,AX ; the source string
|
||
;**********************************************************************
|
||
;* * * Warning: The data segment register (DS) does not point to * * *
|
||
;* * * the data segment in the code which follows * * *
|
||
;**********************************************************************
|
||
pop ES ; make ES point to the data segment
|
||
push ES
|
||
|
||
; Register usage: ES:[DI] - next character in output buffer
|
||
; DS:[SI] - next character in source string
|
||
; BX - number of columns in window
|
||
; CX - current column (cursor position) relative to window
|
||
; DX - end of source string address
|
||
|
||
sd_next: cmp SI,DX ; end of input string?
|
||
jae sd_final ; if end of string, jump
|
||
lodsb ; fetch next character from string
|
||
cmp AL,CTL_Z ; possible control character?
|
||
ja sd_norml ; if not control character, jump
|
||
cmp AL,CTL_A ; nul character?
|
||
jb sd_next ; if nul character, ignore it (jump)
|
||
cmp AL,CTL_I ; tab character?
|
||
jne sd_notab ; if not a tab, jump
|
||
; TAB character-- output a series of blanks
|
||
mov AL," " ; load a blank to store one or more times
|
||
mov AH,CL ; copy cursor position
|
||
sub AH,[BP].sd_linum ; and adjust for line number
|
||
sd_tloop: stosb ; store a blank to the output buffer
|
||
inc CX ; increment the current column number
|
||
inc AH
|
||
test AH,07h ; is next column a multiple of eight?
|
||
jnz sd_tloop ; if not, loop
|
||
jmp sd_test
|
||
; "normal" control character-- prefix with "^"
|
||
sd_notab: mov AH,AL ; save control character
|
||
mov AL,"^" ; load a "^" character and output to buffer
|
||
stosb
|
||
inc CX
|
||
mov AL,AH ; copy control character to AL and
|
||
add AL,"A"-CTL_A ; compute alphabetic for said
|
||
; non- control character-- just copy to output buffer
|
||
sd_norml: stosb ; store character into output buffer
|
||
inc CX ; increment the current column number
|
||
sd_test: cmp CX,BX ; line full?
|
||
jb sd_next ; if more room on current line, loop
|
||
|
||
; Full line buffered-- display it on the screen
|
||
call flush ; display line
|
||
mov AX,[BP].sd_cline ; load the current line number
|
||
cmp AX,[BP].sd_nline ; are we at the end of the screen?
|
||
jl sd_next ; if more lines in window, jump
|
||
; Window full-- set cursor position to last line + 1, column 0
|
||
les SI,dword ptr [BP].sd_wn_SI ; load pointer to window object
|
||
mov ES:[SI].pt_ccol,0 ; set next column number to zero
|
||
mov CX,[BP].sd_cline ; store next line number into window
|
||
mov ES:[SI].pt_cline,CX ; object, too
|
||
jmp sd_fin ; window full, jump
|
||
|
||
; end of string-- output final line
|
||
sd_final: push ES ; save pointer to data segment
|
||
les SI,dword ptr [BP].sd_wn_SI ; load pointer to window object
|
||
mov AX,CX ; save current column
|
||
mov ES:[SI].pt_ccol,CX ; store next column into window object
|
||
mov CX,[BP].sd_cline ; store current line number into window
|
||
mov ES:[SI].pt_cline,CX ; object, too
|
||
pop ES ; restore pointer to data segment
|
||
mov CX,SD_BSIZE-1 ; load buffer length
|
||
sub CX,AX ; subtract number of columns in buffer
|
||
mov AL," " ; load a blank
|
||
rep stosb ; blank the remainder of output buffer
|
||
mov [BP].sd_last,1 ; indicate last line
|
||
call flush ; display to screen
|
||
sd_fin: pop DS ; restore DS
|
||
|
||
;**********************************************************************
|
||
;* * * Warning: The data segment register (DS) does not point to * * *
|
||
;* * * the data segment in the code above * * *
|
||
;**********************************************************************
|
||
|
||
; Operation complete-- return to Scheme interpreter
|
||
sd_done: mov SP,BP ; clean up anything pushed on stack
|
||
add SP,offset sd_BP ; deallocate local storage
|
||
pop BP ; restore Scheme interpreter's BP
|
||
jmp next_PC ; return to Schemem interpreter
|
||
|
||
strdisp endp
|
||
|
||
;************************************************************************
|
||
;* Local Support: Flush Output Buffer to Screen *
|
||
;* *
|
||
;* Input Parameters: ES - points to data segment *
|
||
;************************************************************************
|
||
public flush
|
||
flush proc near
|
||
pushm <DS,SI,DI,CX,DX> ; save valuable registers
|
||
; Make DS register point to data segment
|
||
mov AX,ES
|
||
mov DS,AX
|
||
|
||
; Test for negative bias
|
||
inc [BP].sd_bias ; increment and test "bias" value
|
||
jg fl_no_bs ; if zero or positive, no bias (jump)
|
||
jmp fl_bias ; if negative, don't display current line
|
||
; Position the cursor in the current column position
|
||
fl_no_bs: mov DL,byte ptr [BP].sd_cline ; load the current cursor
|
||
mov DH,byte ptr [BP].sd_ccol ; position
|
||
add DL,byte ptr [BP].sd_ullin ; adjust cursor positon by
|
||
add DH,byte ptr [BP].sd_ulcol ; coordinates of upper left corner
|
||
mov [BP].sd_cursv,DX ; save the cursor coordinates
|
||
IFNDEF PROMEM
|
||
xor BH,BH ; IBMism (page 0 for text-mode)
|
||
mov AH,02h ; load "put cursor" code
|
||
call CRT_DSR ; put cursor at current position
|
||
ENDIF
|
||
; Display the line
|
||
mov CX,[BP].sd_ncols ; load line length
|
||
sub CX,[BP].sd_ccol ; subtract starting column offset
|
||
; Replace the "last" character in line with an exclamation mark
|
||
cmp [BP].sd_last,0 ; last line to be output?
|
||
jnz fl_last ; if last line, leave character alone (jump)
|
||
mov SI,CX ; copy character count
|
||
mov AL,"!" ; load an exclamation mark
|
||
xchg AL,[BP]+sd_buff+[SI]-1 ; swap with final character in line
|
||
mov [BP].sd_char,AL ; save character to later viewing
|
||
|
||
public fl_last
|
||
fl_last label near
|
||
IFDEF PROMEM
|
||
buffer_is_stack ;treat comm buffer as stack
|
||
mov [BP].sd_len,cx ;save character count
|
||
REALIO REAL_WRTBLOCK,sd_len,sd_cursv,continue
|
||
buffer_is_buffer ;treat comm buffer as buffer
|
||
ELSE
|
||
; Determine PC make
|
||
cmp PC_MAKE,TIPC ; on what flavor PC are we running?
|
||
jne fl_ibm ; if an IBM, jump
|
||
; Write line to TIPC's screen
|
||
mov AL,byte ptr [BP].sd_text ; load text attributes
|
||
mov AH,010h ; load "write block w/ attr" code
|
||
mov DX,DS ; load segment address
|
||
mov BX,BP
|
||
add BX,sd_buff ; load buffer offset in segment
|
||
int TI_CRT ; write the buffer
|
||
jmp fl_back
|
||
|
||
; Write line to IBM's screen
|
||
fl_ibm: mov DI,BP
|
||
add DI,sd_buff ; load buffer offset
|
||
mov DX,[BP].sd_cursv ; reverse row/column coordinates
|
||
xchg DL,DH
|
||
mov [BP].sd_cursv,DX
|
||
push CX ; save the character counter
|
||
jmp short fl_imidl ; jump into middle of loop
|
||
|
||
fl_iloop: push CX ; save the character counter
|
||
mov DX,[BP].sd_cursv ; load the previous cursor coordinates,
|
||
inc DL ; increment the column number
|
||
mov [BP].sd_cursv,DX ; and save new coordinates
|
||
xor BH,BH ; page number (0 for graphics mode) IBMism
|
||
mov AH,02h ; load "put cursor" code
|
||
push DI
|
||
int IBM_CRT
|
||
pop DI
|
||
fl_imidl: mov AH,09h ; Load "write char w/ attributes" code
|
||
mov AL,byte ptr [DI] ; load character from buffer
|
||
mov BL,byte ptr [BP].sd_text ; load attribute bits
|
||
xor BH,BH ; page # for alpha mode
|
||
mov CX,1 ; load repeat count = 1
|
||
; test to see if we buy anything by using a repeat count
|
||
pop DX ; restore character count
|
||
fl_imore: cmp DX,1 ; more characters to display?
|
||
jle fl_ibotm ; if no more characters, jump
|
||
cmp AL,byte ptr [DI]+1 ; is next character the same as previous?
|
||
jne fl_ibotm ; if not same character, jump
|
||
inc CX ; increment the repeat count
|
||
inc DI ; increment the output buffer index
|
||
inc byte ptr [BP].sd_cursv ; increment the cursor position
|
||
dec DX ; decrement the character count
|
||
jmp fl_imore ; try for another
|
||
fl_ibotm: push DX ; save the adjusted character count
|
||
; output the character(s)
|
||
push DI ; save the output buffer index
|
||
int IBM_CRT ; write character with attributes
|
||
pop DI ; restore the output buffer index
|
||
pop CX ; restore character counter
|
||
inc DI ; increment buffer pointer
|
||
loop fl_iloop ; continue 'til all characters output
|
||
ENDIF
|
||
|
||
; Restore last character in line to its rightful value
|
||
fl_back: mov SI,[BP].sd_ncols
|
||
sub SI,[BP].sd_ccol
|
||
mov AL,[BP].sd_char
|
||
mov [BP]+sd_buff+[SI]-1,AL
|
||
|
||
; Shift buffer to remove the line just displayed
|
||
inc [BP].sd_cline ; increment the line number
|
||
fl_bias: mov SI,[BP].sd_ncols ; compute number of characters just output
|
||
sub SI,[BP].sd_ccol ; (unless bias < 0, in which case we just
|
||
dec SI ; branched here)
|
||
push SI ; save character count
|
||
mov CX,10 ; make up a character count for move
|
||
mov DI,BP ; load address of buffer start
|
||
add DI,sd_buff
|
||
add SI,BP ; load address of leftover characters
|
||
add si,sd_buff
|
||
rep movsb ; shift any characters left over
|
||
mov BX,[BP].sd_ccol ;;; new code for fix
|
||
;;; save the current column for adjust
|
||
mov [BP].sd_ccol,0 ; set current column to zero
|
||
inc [BP].sd_linum ; increment formatting line number
|
||
|
||
; Reset Active Registers to reflect shifted buffer
|
||
pop AX ; restore output character count
|
||
popm <DX,CX,DI,SI> ; restore control registers
|
||
sub DI,AX ; adjust buffer index
|
||
sub CX,AX ; adjust current column
|
||
sub CX,BX ;;; new code for fix
|
||
;;; adjust current column
|
||
mov BX,[BP].sd_ncols ; reload line length
|
||
pop DS ; restore DS register
|
||
ret ; return
|
||
flush endp
|
||
|
||
;************************************************************************
|
||
;* Local Support: Fetch and Validate Integer Argument *
|
||
;* *
|
||
;* Input Parameters: BX - address of register containing the integer *
|
||
;* argument *
|
||
;* *
|
||
;* Output Parameters: If CARRY off, normal return: *
|
||
;* AX - the 16 bit positive integer value *
|
||
;* If CARRY on, error: *
|
||
;* AX - the error condition; 0=operand not an *
|
||
;* integer; 1=integer operand was negative *
|
||
;* or larger than 16 bits. *
|
||
;************************************************************************
|
||
public get_num
|
||
get_num proc near
|
||
; test for a fixnum argument
|
||
cmp byte ptr [BX].C_page,SPECFIX*2 ; fixnum?
|
||
jne big_p ; if not a fixnum, test for bignum (jump)
|
||
mov AX,[BX].C_disp ; load immediate value of fixnum
|
||
test AX,04000h ; negative?
|
||
jnz get_val ; if negative, error (jump)
|
||
ret ; if positive, return with value in AX
|
||
|
||
; test for a bignum argument
|
||
big_p: mov SI,[BX].C_page ; load page number of argument
|
||
cmp byte ptr ptype+[SI],BIGTYPE*2 ; is argument a bignum?
|
||
jne get_type ; if not a bignum, invalid type (jump)
|
||
%LoadPage ES,SI
|
||
;;; mov ES,pagetabl+[SI] ; load paragraph address of bignum's page
|
||
mov SI,[BX].C_disp ; load displacement of bignum
|
||
cmp ES:[SI].big_sign,0 ; test sign of bignum
|
||
jne get_val ; if negative, error (jump)
|
||
cmp ES:[SI].big_len,BLK_OVHD+WORDINCR+1 ; test size of bignum
|
||
jne get_val ; if too large, error (jump)
|
||
mov AX,ES:[SI].big_data ; load 16 bit value of bignum
|
||
clc
|
||
ret ; return with value in AX
|
||
; ***error-- operand is not an integer***
|
||
get_type: mov AX,0 ; indicate operand wrong type
|
||
jmp short get_err
|
||
; ***error-- integer operand is negative, or too large***
|
||
get_val: mov AX,1
|
||
get_err: stc
|
||
ret
|
||
get_num endp
|
||
|
||
;************************************************************************
|
||
;* Local Support: Return a 16 bit positive integer value *
|
||
;* *
|
||
;* Input Parameters: BX - address of destination register *
|
||
;* SI - 16 bit unsigned integer value to be returned *
|
||
;* *
|
||
;* Output Parameters: The Scheme representation of the 16 bit unsigned *
|
||
;* value is placed into the destination register. *
|
||
;************************************************************************
|
||
public ret_num
|
||
ret_num proc near
|
||
cmp SI,03fffh ; can result be represented as a fixnum?
|
||
ja make_big ; if not, create a bignum
|
||
; return a fixnum result
|
||
mov byte ptr [BX].C_page,SPECFIX*2 ; set tag=fixnum
|
||
mov [BX].C_disp,SI ; store value
|
||
ret ; return
|
||
; return a bignum result
|
||
make_big:
|
||
push SI ; save value around call
|
||
push BX ; save destination reg also
|
||
|
||
mov CX,WORDINCR+1 ; load size of bignum desired
|
||
mov AX,BIGTYPE ; load type = bignum
|
||
pushm <CX,AX,BX> ; push arguments to allocate block
|
||
call %allocbl ; allocate the bignum
|
||
add SP,WORDINCR*3 ; drop arguments off stack
|
||
|
||
pop BX ; restore destination reg
|
||
mov SI,[BX].C_page ; get page number of new bignum
|
||
%LoadPage ES,SI ; and fetch its segment address
|
||
mov SI,[BX].C_disp ; load the bignum's displacement
|
||
mov ES:[SI].big_sign,0 ; set bignum's sign to '+'
|
||
pop AX ; restore value and
|
||
mov ES:[SI].big_data,AX ; store it into the bignum
|
||
ret ; return
|
||
ret_num endp
|
||
|
||
|
||
PROGX ends
|
||
|
||
prog segment byte public 'PROG'
|
||
assume CS:PGROUP
|
||
;************************************************************************
|
||
;* Long Linkage to SUBSTRING-FIND-NEXT-CHAR-IN-SET *
|
||
;************************************************************************
|
||
public srch_nxt
|
||
srch_nxt proc near
|
||
call %srchnxt
|
||
ret
|
||
srch_nxt endp
|
||
|
||
;************************************************************************
|
||
;* Long Linkage to SUBSTRING-FIND-PREVIOUS-CHAR-IN-SET *
|
||
;************************************************************************
|
||
public srch_prv
|
||
srch_prv proc near
|
||
call %srchprv
|
||
ret
|
||
srch_prv endp
|
||
|
||
;************************************************************************
|
||
;* Long Linkage to STRING-LENGTH *
|
||
;************************************************************************
|
||
public st_len
|
||
st_len proc near
|
||
call %st_len
|
||
ret
|
||
st_len endp
|
||
|
||
;************************************************************************
|
||
;* Long Linkage to MAKE-STRING *
|
||
;************************************************************************
|
||
;;; public make_str
|
||
make_str proc near
|
||
call %makestr
|
||
ret
|
||
make_str endp
|
||
|
||
;************************************************************************
|
||
;* Long Linkage to REIFY_STACK *
|
||
;************************************************************************
|
||
public reif_stk
|
||
reif_stk proc near
|
||
call %reifstk
|
||
ret
|
||
reif_stk endp
|
||
|
||
;************************************************************************
|
||
;* Long Linkage to REIFY_STACK! *
|
||
;************************************************************************
|
||
public reif_stb
|
||
reif_stb proc near
|
||
call %reifstb
|
||
ret
|
||
reif_stb endp
|
||
|
||
prog ends
|
||
end
|
||
|