651 lines
28 KiB
NASM
651 lines
28 KiB
NASM
|
; =====> SCAR_CDR.ASM
|
|||
|
;***************************************
|
|||
|
;* TIPC Scheme '84 Runtime Support *
|
|||
|
;*Interpreter -- Car and Cdr operations*
|
|||
|
;* *
|
|||
|
;* (C) Copyright 1984,1985,1986 by *
|
|||
|
;* Texas Instruments Incorporated. *
|
|||
|
;* All rights reserved. *
|
|||
|
;* *
|
|||
|
;* Date Written: 11 September 1984 *
|
|||
|
;* Last Modification: 26 February 1986*
|
|||
|
;***************************************
|
|||
|
include scheme.equ
|
|||
|
|
|||
|
; Modification History:
|
|||
|
; 26 Feb 86 - modified the "CONS" support to attempt a "short circuit"
|
|||
|
; (JCJ) allocation of a list cell, instead of calling the
|
|||
|
; "alloc_list_cell" support unconditionally.
|
|||
|
|
|||
|
include sinterp.mac
|
|||
|
include sinterp.arg
|
|||
|
|
|||
|
take_car macro
|
|||
|
cmp byte ptr ptype+[BX],LISTTYPE*2
|
|||
|
jne bad_car
|
|||
|
LoadPage ES,BX
|
|||
|
;;; mov ES,pagetabl+[BX]
|
|||
|
mov BL,ES:[SI].car_page
|
|||
|
mov SI,ES:[SI].car
|
|||
|
endm
|
|||
|
|
|||
|
take_cdr macro
|
|||
|
cmp byte ptr ptype+[BX],LISTTYPE*2
|
|||
|
jne bad_cdr
|
|||
|
LoadPage ES,BX
|
|||
|
;;; mov ES,pagetabl+[BX]
|
|||
|
mov BL,ES:[SI].cdr_page
|
|||
|
mov SI,ES:[SI].cdr
|
|||
|
endm
|
|||
|
|
|||
|
; load arguments for cxr
|
|||
|
load_arg macro
|
|||
|
lods word ptr ES:[SI] ; fetch source/destination register numbers
|
|||
|
save <SI> ; save the location pointer
|
|||
|
mov BL,AH ; copy the source register number
|
|||
|
mov SI,reg0_dis+[BX] ; load contents of the source register
|
|||
|
mov BL,byte ptr reg0_pag+[BX]
|
|||
|
endm
|
|||
|
|
|||
|
car_cdr2 macro arg1,arg2
|
|||
|
mov CX,offset PGROUP:arg1&_last
|
|||
|
mov DI,offset PGROUP:arg2&_CX
|
|||
|
jmp load_ops
|
|||
|
endm
|
|||
|
|
|||
|
car_cdr3 macro arg1,arg2,arg3
|
|||
|
mov DX,offset PGROUP:arg1&_last
|
|||
|
mov CX,offset PGROUP:arg2&_DX
|
|||
|
mov DI,offset PGROUP:arg3&_CX
|
|||
|
jmp load_ops
|
|||
|
endm
|
|||
|
|
|||
|
DGROUP group data
|
|||
|
data segment word public 'DATA'
|
|||
|
assume DS:DGROUP
|
|||
|
m_car db "CAR",0
|
|||
|
m_cdr db "CDR",0
|
|||
|
m_caar db "CAAR",0
|
|||
|
m_cadr db "CADR",0
|
|||
|
m_cdar db "CDAR",0
|
|||
|
m_cddr db "CDDR",0
|
|||
|
m_caaar db "CAAAR",0
|
|||
|
m_caadr db "CAADR",0
|
|||
|
m_cadar db "CADAR",0
|
|||
|
m_caddr db "CADDR",0
|
|||
|
m_cdaar db "CDAAR",0
|
|||
|
m_cdadr db "CDADR",0
|
|||
|
m_cddar db "CDDAR",0
|
|||
|
m_cdddr db "CDDDR",0
|
|||
|
m_cadddr db "CADDDR",0
|
|||
|
m_%car db "%CAR",0
|
|||
|
m_%cdr db "%CDR",0
|
|||
|
|
|||
|
m_table dw m_car,m_cdr,m_caar,m_cadr,m_cdar,m_cddr,m_caaar,m_caadr
|
|||
|
dw m_cadar,m_caddr,m_cdaar,m_cdadr,m_cddar,m_cdddr,m_cadddr
|
|||
|
|
|||
|
m_setcar db "SET-CAR!",0
|
|||
|
m_setcdr db "SET-CDR!",0
|
|||
|
m_apendb db "APPEND!",0
|
|||
|
m_ltail db "LIST_TAIL",0
|
|||
|
m_one dw 1 ; a constant "one" (1)
|
|||
|
m_two dw 2 ; a constant "two" (2)
|
|||
|
m_three dw 3 ; a constant "three" (3)
|
|||
|
data ends
|
|||
|
|
|||
|
PGROUP group prog
|
|||
|
prog segment byte public 'PROG'
|
|||
|
assume CS:PGROUP
|
|||
|
|
|||
|
car_cdr proc near
|
|||
|
|
|||
|
; Entry points defined in "sinterp.asm"
|
|||
|
extrn next:near ; Top of interpreter
|
|||
|
extrn next_PC:near ; Reload ES,SI at top of interpreter
|
|||
|
extrn next_SP:near ; Reload SP,ES,SI at top of interpreter
|
|||
|
extrn src_err:near ; "source operand error" message display
|
|||
|
extrn sch_err:near ; "source operand error" message display
|
|||
|
extrn printf_c:near ; Error message print routine
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* %car %CAR DEST *
|
|||
|
;* *
|
|||
|
;* Purpose: To obtain the first element of a list. This support is *
|
|||
|
;* similar to the usual "car" operation except that %car *
|
|||
|
;* returns #!unassigned if one tries to take the car of *
|
|||
|
;* nil. *
|
|||
|
;************************************************************************
|
|||
|
public ld_car1
|
|||
|
ld_car1: lods byte ptr ES:[SI] ; load operand
|
|||
|
save <SI> ; save the location pointer
|
|||
|
mov BX,AX ; copy operand register number to BX
|
|||
|
mov SI,reg0_dis+[BX] ; load the source operand
|
|||
|
mov BL,byte ptr reg0_pag+[BX]
|
|||
|
cmp byte ptr ptype+[BX],LISTTYPE*2
|
|||
|
jne bad_car1 ; if not a list cell, error (jump)
|
|||
|
cmp BL,0 ; is source operand nil?
|
|||
|
jne car_last ; if not nil, jump
|
|||
|
cxr_undf: mov BX,AX ; reload dest register number
|
|||
|
mov byte ptr reg0_pag+[BX],UN_PAGE*2 ; set destination reg
|
|||
|
mov reg0_dis+[BX],UN_DISP ; to #!unassigned
|
|||
|
jmp next_PC
|
|||
|
bad_car1: mov AX,offset m_%car
|
|||
|
jmp bad_one
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* %cdr %CDR DEST *
|
|||
|
;* *
|
|||
|
;* Purpose: To obtain the rest of a list. This support is similar *
|
|||
|
;* to the usual "cdr" operation except that %cdr returns *
|
|||
|
;* #!unassigned if one tries to take the cdr of nil. *
|
|||
|
;************************************************************************
|
|||
|
public ld_cdr1
|
|||
|
ld_cdr1: lods byte ptr ES:[SI] ; load operand
|
|||
|
save <SI> ; save the location pointer
|
|||
|
mov BX,AX ; copy operand register number to BX
|
|||
|
mov SI,reg0_dis+[BX] ; load the source operand
|
|||
|
mov BL,byte ptr reg0_pag+[BX]
|
|||
|
cmp BL,0 ; is source operand nil?
|
|||
|
je cxr_undf ; if nil, return #!unassigned (jump)
|
|||
|
cmp byte ptr ptype+[BX],LISTTYPE*2
|
|||
|
je cdr_last ; if a list cell, continue processing (jump)
|
|||
|
jmp bad_cdr1 ; if not a list cell, error (jump)
|
|||
|
bad_cdr1: mov AX,offset m_%cdr
|
|||
|
jmp bad_one
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "car" of a list cell LD_CAR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_car
|
|||
|
ld_car: load_arg
|
|||
|
car_last: cmp byte ptr ptype+[BX],LISTTYPE*2
|
|||
|
jne bad_car ; if not a list cell, error (jump)
|
|||
|
LoadPage ES,BX
|
|||
|
;;; mov ES,pagetabl+[BX] ; load para addr of page containing cell
|
|||
|
mov BL,AL ; copy destination register number
|
|||
|
mov AL,ES:[SI].car_page ; copy contents of car field into
|
|||
|
mov byte ptr reg0_pag+[BX],AL ; the destination register
|
|||
|
mov AX,ES:[SI].car
|
|||
|
mov reg0_dis+[BX],AX
|
|||
|
jmp next_PC ; return to the interpreter
|
|||
|
|
|||
|
car_CX: take_car
|
|||
|
jmp CX
|
|||
|
|
|||
|
car_DX: take_car
|
|||
|
jmp DX
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "cdr" of a list cell LD_CDR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_cdr
|
|||
|
ld_cdr: load_arg
|
|||
|
cdr_last: cmp byte ptr ptype+[BX],LISTTYPE*2
|
|||
|
jne bad_cdr ; if not a list cell, error (jump)
|
|||
|
LoadPage ES,BX
|
|||
|
;;; mov ES,pagetabl+[BX] ; load para addr of page containing cell
|
|||
|
mov BL,AL ; copy destination register number
|
|||
|
mov AL,ES:[SI].cdr_page ; copy contents of cdr field into
|
|||
|
mov byte ptr reg0_pag+[BX],AL ; the destination register
|
|||
|
mov AX,ES:[SI].cdr
|
|||
|
mov reg0_dis+[BX],AX
|
|||
|
jmp next_PC ; return to the interpreter
|
|||
|
|
|||
|
|
|||
|
; ***Error-- attempt to take "car" of non- list cell***
|
|||
|
bad_car:
|
|||
|
; ***Error-- attempt to take "cdr" of non- list cell***
|
|||
|
bad_cdr: les SI,dword ptr [BP].save_SI ; load next instruction's address
|
|||
|
xor BX,BX ; load opcode of failing instruction
|
|||
|
mov BL,ES:[SI]-3
|
|||
|
shl BX,1
|
|||
|
mov AX,m_table+[BX]-128
|
|||
|
bad_one: les SI,dword ptr [BP].save_SI ; load next instruction's address
|
|||
|
xor BX,BX
|
|||
|
mov BL,ES:[SI]-1 ; load register used as last operand
|
|||
|
add BX,offset reg0
|
|||
|
pushm <BX,m_one,AX>
|
|||
|
C_call set_src_,,Load_ES
|
|||
|
jmp sch_err ; display error message
|
|||
|
|
|||
|
cdr_CX: take_cdr
|
|||
|
jmp CX
|
|||
|
|
|||
|
cdr_DX: take_cdr
|
|||
|
jmp DX
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "cadddr" of a list cell LD_CADDDR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_caddd
|
|||
|
ld_caddd: load_arg
|
|||
|
take_cdr
|
|||
|
mov DX,offset PGROUP:car_last
|
|||
|
mov CX,offset PGROUP:cdr_DX
|
|||
|
jmp cdr_CX
|
|||
|
|
|||
|
load_ops: load_arg
|
|||
|
jmp DI
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "caar" of a list cell LD_CAAR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_caar
|
|||
|
ld_caar: car_cdr2 car,car
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "cadr" of a list cell LD_CADR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_cadr
|
|||
|
ld_cadr: car_cdr2 car,cdr
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "cdar" of a list cell LD_CDAR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_cdar
|
|||
|
ld_cdar: car_cdr2 cdr,car
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "cddr" of a list cell LD_CDDR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_cddr
|
|||
|
ld_cddr: car_cdr2 cdr,cdr
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "caaar" of a list cell LD_CAAAR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_caaar
|
|||
|
ld_caaar: car_cdr3 car,car,car
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "caadr" of a list cell LD_CAADR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_caadr
|
|||
|
ld_caadr: car_cdr3 car,car,cdr
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "cadar" of a list cell LD_CADAR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_cadar
|
|||
|
ld_cadar: car_cdr3 car,cdr,car
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "caddr" of a list cell LD_CADDR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_caddr
|
|||
|
ld_caddr: car_cdr3 car,cdr,cdr
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "cdaar" of a list cell LD_CDAAR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_cdaar
|
|||
|
ld_cdaar: car_cdr3 cdr,car,car
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "cdadr" of a list cell LD_CDADR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_cdadr
|
|||
|
ld_cdadr: car_cdr3 cdr,car,cdr
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "cddar" of a list cell LD_CDDAR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_cddar
|
|||
|
ld_cddar: car_cdr3 cdr,cdr,car
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Take "cdddr" of a list cell LD_CDDDR dest,src *
|
|||
|
;************************************************************************
|
|||
|
public ld_cdddr
|
|||
|
ld_cdddr: car_cdr3 cdr,cdr,cdr
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* Macro support for set-car!/set-cdr! *
|
|||
|
;************************************************************************
|
|||
|
set_cc macro field
|
|||
|
local x
|
|||
|
lods word ptr ES:[SI] ; load register numbers
|
|||
|
mov DX,ES ; save TIPC register ES
|
|||
|
mov BL,AL
|
|||
|
mov DI,reg0_pag+[BX] ; load dest register page number
|
|||
|
cmp DI,0 ; are we trying to set car/cdr of nil?
|
|||
|
je x ; if (set-cxr nil v), error (jump)
|
|||
|
cmp byte ptr ptype+[DI],LISTTYPE*2 ; Is destination a list cell?
|
|||
|
jne x ; If not, set_field! not defined
|
|||
|
LoadPage ES,DI
|
|||
|
;;; mov ES,pagetabl+[DI] ; Load paragraph addr for dest page
|
|||
|
mov DI,reg0_dis+[BX] ; Load destination displacement
|
|||
|
mov BL,AH ; Copy src register number
|
|||
|
mov AL,byte ptr reg0_pag+[BX] ; redefine field's page number
|
|||
|
mov ES:[DI].&field&_page,AL
|
|||
|
mov AX,reg0_dis+[BX] ; redefine field's displacement
|
|||
|
mov ES:[DI].&field,AX
|
|||
|
mov ES,DX ; reload ES segment register
|
|||
|
jmp next
|
|||
|
x: mov BX,offset m_set&field ; load address of message text
|
|||
|
IFIDN <&field>,<car>
|
|||
|
bad_stcr: mov ES,DX
|
|||
|
bad_st1: xor AX,AX
|
|||
|
mov AL,ES:[SI]-1
|
|||
|
add AX,offset reg0
|
|||
|
push AX
|
|||
|
xor AX,AX
|
|||
|
mov AL,ES:[SI]-2
|
|||
|
add AX,offset reg0
|
|||
|
pushm <AX,m_two,BX>
|
|||
|
C_call set_src_,<SI>,Load_ES
|
|||
|
restore <SI>
|
|||
|
jmp sch_err
|
|||
|
ELSE
|
|||
|
jmp bad_stcr
|
|||
|
ENDIF
|
|||
|
endm
|
|||
|
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Side effect car field (set-car! dest src) SET-CAR! dest,src *
|
|||
|
;* *
|
|||
|
;* Purpose: Interpreter support for the set-car! operation. *
|
|||
|
;************************************************************************
|
|||
|
public set_car
|
|||
|
set_car: set_cc car
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* Side effect cdr field (set-cdr! dest src) SET-CDR! dest,src *
|
|||
|
;* *
|
|||
|
;* Purpose: Interpreter support for the set-cdr! operation. *
|
|||
|
;************************************************************************
|
|||
|
public set_cdr
|
|||
|
set_cdr: set_cc cdr
|
|||
|
|
|||
|
purge set_cc
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* DL DH AL *
|
|||
|
;* Cons - Create and define new list cell CONS dest,car,cdr *
|
|||
|
;* *
|
|||
|
;* Purpose: Interpreter support for the Scheme "cons" operation. *
|
|||
|
;************************************************************************
|
|||
|
public s_cons
|
|||
|
s_cons: lods word ptr ES:[SI] ; load destination/car register numbers
|
|||
|
mov DX,AX ; and save in DX
|
|||
|
xor AX,AX
|
|||
|
lods byte ptr ES:[SI] ; load cdr register number
|
|||
|
save <SI> ; save the location pointer
|
|||
|
; Attempt a "short circuit" list cell allocation
|
|||
|
mov DI,listpage
|
|||
|
;;; cmp DI,END_LIST
|
|||
|
;;; je cons_no
|
|||
|
shl DI,1
|
|||
|
mov SI,nextcell+[DI]
|
|||
|
cmp SI,END_LIST
|
|||
|
je cons_no
|
|||
|
LoadPage ES,DI
|
|||
|
;;; mov ES,pagetabl+[DI] ; load list cell page's segment address
|
|||
|
mov CX,ES:[SI].car
|
|||
|
mov nextcell+[DI],CX
|
|||
|
; Move contents of CDR register to CDR field of new list cell
|
|||
|
cons_ok: mov BX,AX ; copy register number to BX
|
|||
|
mov AL,byte ptr reg0_pag+[BX]
|
|||
|
mov ES:[SI].cdr_page,AL
|
|||
|
mov AX,reg0_dis+[BX]
|
|||
|
mov ES:[SI].cdr,AX
|
|||
|
; Move contents of CAR register to CAR field of new list cell
|
|||
|
mov BL,DH ; copy CAR register number to BX
|
|||
|
mov AL,byte ptr reg0_pag+[BX]
|
|||
|
mov ES:[SI].car_page,AL
|
|||
|
mov AX,reg0_dis+[BX]
|
|||
|
mov ES:[SI].car,AX
|
|||
|
; Update destination register number with pointer to new list cell
|
|||
|
mov BL,DL
|
|||
|
mov reg0_pag+[BX],DI
|
|||
|
mov reg0_dis+[BX],SI
|
|||
|
jmp next_SP
|
|||
|
|
|||
|
; "short circuit" list cell allocation failed-- go through channels
|
|||
|
cons_no: push tmp_adr
|
|||
|
C_call alloc_li,<AX,DX>,Load_ES
|
|||
|
add SP,WORDINCR
|
|||
|
restore <AX,DX>
|
|||
|
mov DI,tmp_page
|
|||
|
mov SI,tmp_disp
|
|||
|
LoadPage ES,DI
|
|||
|
;;; mov ES,pagetabl+[DI]
|
|||
|
jmp cons_ok
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* List - Create and define new list cell w/ nil cdr LIST dest *
|
|||
|
;* *
|
|||
|
;* Purpose: Interpreter support for the Scheme "list" operation. *
|
|||
|
;************************************************************************
|
|||
|
public s_list
|
|||
|
s_list: lods byte ptr ES:[SI] ; load destination register number
|
|||
|
mov BX,offset tmp_reg ; load address of temporary register
|
|||
|
pushm <AX,BX> ; push dest reg number, temp_reg address
|
|||
|
C_call alloc_li,<SI>,Load_ES ; allocate list cell
|
|||
|
add SP,WORDINCR ; dump argument from TIPC's stack
|
|||
|
pop SI ; restore destination register pointer
|
|||
|
mov BX,tmp_page ; load page number of new list cell
|
|||
|
mov CX,BX
|
|||
|
LoadPage ES,BX
|
|||
|
;;; mov ES,pagetabl+[BX] ; load list cell's page table address
|
|||
|
mov DI,tmp_disp ; load displacement of new list cell
|
|||
|
; copy car field into newly allocated list cell
|
|||
|
mov AX,reg0_dis+[SI] ; load car's displacement, and
|
|||
|
mov ES:[DI].car,AX ; store into new list cell
|
|||
|
mov AL,byte ptr reg0_pag+[SI] ; load page number, and
|
|||
|
mov ES:[DI].car_page,AL ; store it, too
|
|||
|
; create nil cdr field into newly allocated list cell
|
|||
|
xor AX,AX
|
|||
|
mov ES:[DI].cdr,AX
|
|||
|
mov ES:[DI].cdr_page,AL
|
|||
|
; copy pointer to new list cell into destination register
|
|||
|
mov byte ptr reg0_pag+[SI],CL
|
|||
|
mov reg0_dis+[SI],DI
|
|||
|
jmp next_PC
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* AL AH *
|
|||
|
;* (list a b) LIST2 dest,src *
|
|||
|
;* *
|
|||
|
;* Purpose: Interpreter support for the (list a b) operation. *
|
|||
|
;* *
|
|||
|
;* Description: This operation: (list a b) *
|
|||
|
;* is equivalent to: (cons a (cons b nil)) *
|
|||
|
;************************************************************************
|
|||
|
public list2
|
|||
|
list2: lods word ptr ES:[SI] ; fetch operands
|
|||
|
mov BL,AL ; save the destination register number
|
|||
|
push BX
|
|||
|
mov BL,AH ; copy the source register number
|
|||
|
add BX,offset reg0 ; compute source register address
|
|||
|
mov AX,offset nil_reg ; load "nil_reg" address
|
|||
|
mov CX,offset tmp_reg ; load "tmp_reg" address
|
|||
|
pushm <AX,BX,CX> ; push arguments to cons
|
|||
|
C_call cons,<SI>,Load_ES ; call: cons(tmp_reg,src,nil_reg)
|
|||
|
pop CX ; restore tmp_reg address
|
|||
|
add SP,WORDINCR*2 ; drop arguments from TIPC's stack
|
|||
|
pop BX ; restore destination register number
|
|||
|
add BX,offset reg0 ; compute destination register address
|
|||
|
pushm <CX,BX,BX> ; push arguments to cons
|
|||
|
C_call cons ; call: cons(dest, dest, tmp_reg)
|
|||
|
jmp next_SP ; return to the interpreter
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* (append! list obj) append! dest src *
|
|||
|
;* *
|
|||
|
;* Purpose: Scheme interpreter support for the append! primitive *
|
|||
|
;************************************************************************
|
|||
|
public appendb
|
|||
|
appendb: lods word ptr ES:[SI] ; get args (AL=arg1, AH=arg2)
|
|||
|
save <SI> ; save the location pntr
|
|||
|
mov BL,AL
|
|||
|
lea DI,reg0+[BX] ; DI=address of dest reg
|
|||
|
mov BX,[DI].C_page ; load list header from dest reg
|
|||
|
cmp byte ptr ptype+[BX],LISTTYPE*2 ; is arg1 a list?
|
|||
|
jne short not_list ; if not, error (jump)
|
|||
|
;
|
|||
|
cmp BL,NIL_PAGE*2 ; is arg1 == nil?
|
|||
|
jne short find_end ; if not, continue (jump)
|
|||
|
;
|
|||
|
mov BL,AH ; else get 2nd arg & return it in dest reg
|
|||
|
lea SI,reg0+[BX] ; SI=address of src reg
|
|||
|
mov BX,[SI].C_page ; Copy src reg to dest reg
|
|||
|
mov [DI].C_page,BX
|
|||
|
mov BX,[SI].C_disp
|
|||
|
mov [DI].C_disp,BX
|
|||
|
jmp next_PC ; RETURN
|
|||
|
;
|
|||
|
find_end label near
|
|||
|
mov CX,SB_CHECK ; load shift-break iteration count
|
|||
|
mov DI,[DI].C_disp
|
|||
|
next_cell label near
|
|||
|
LoadPage ES,BX
|
|||
|
;;; mov ES,pagetabl+[BX] ; load list cell page para address
|
|||
|
mov BL,ES:[DI].cdr_page ; load list cell's cdr's page
|
|||
|
cmp BL,NIL_PAGE*2 ; CDR == nil?
|
|||
|
je short eolist ; then end-of-list (jump)
|
|||
|
cmp byte ptr ptype+[BX],LISTTYPE*2 ; still pointing to cons nodes?
|
|||
|
jne short weird_lst
|
|||
|
mov DI,ES:[DI].cdr ; load list cell's cdr's displacement
|
|||
|
loop next_cell
|
|||
|
; Every one in awhile, check for shift-break
|
|||
|
mov CX,SB_CHECK ; reload the shift-break iteration count
|
|||
|
cmp s_break,0 ; has the shift-break key been depressed?
|
|||
|
je next_cell ; if no shift-break, jump
|
|||
|
push m_three ; push instruction length = 3
|
|||
|
C_call restart ; link to Scheme debugger
|
|||
|
; Note: control does not return from "restart"
|
|||
|
;
|
|||
|
weird_lst label near ; possible error checking here
|
|||
|
; as list was non-nil terminated
|
|||
|
eolist label near
|
|||
|
mov BL,AH ; else get 2nd arg & return it in dest reg
|
|||
|
lea SI,reg0+[BX] ; SI=address of src reg
|
|||
|
mov BX,[SI].C_page ; Copy src reg to dest reg
|
|||
|
; check page # for src?
|
|||
|
mov ES:[DI].cdr_page,BL
|
|||
|
mov BX,[SI].C_disp
|
|||
|
mov ES:[DI].cdr,bx
|
|||
|
jmp next_PC ; return to interpreter
|
|||
|
|
|||
|
not_list label near
|
|||
|
mov BX,offset m_apendb
|
|||
|
jmp bad_st1
|
|||
|
|
|||
|
;************************************************************************
|
|||
|
;* (list_tail list count) l_tail list(dest) count *
|
|||
|
;* *
|
|||
|
;* Purpose: Scheme interpreter support for the list_tail primitive *
|
|||
|
;************************************************************************
|
|||
|
|
|||
|
lt_args struc
|
|||
|
COUNT dw ? ; Long integer count of list element
|
|||
|
dw ?
|
|||
|
REGSAVE dw ?
|
|||
|
BP_SAVE dw ? ; Saved base pointer
|
|||
|
ES_SAVE dw ? ; Saved ES reg
|
|||
|
lt_args ends
|
|||
|
|
|||
|
public l_tail
|
|||
|
l_tail:
|
|||
|
lods word ptr ES:[SI] ; get register operands
|
|||
|
save <SI> ; save instruction pointer
|
|||
|
|
|||
|
push ES ; save local registers
|
|||
|
push BP
|
|||
|
sub SP,offset BP_SAVE ; allocate local storage
|
|||
|
mov BP,SP
|
|||
|
|
|||
|
xor BH,BH
|
|||
|
mov BL,AL
|
|||
|
add BX,offset reg0 ; reg holding list ptr
|
|||
|
mov [BP].REGSAVE,BX ; save for later
|
|||
|
|
|||
|
xor BH,BH
|
|||
|
mov BL,AH
|
|||
|
add BX,offset reg0 ; get register containing count
|
|||
|
push BX ; and push for call
|
|||
|
lea BX,[BP+COUNT] ; get location for return value
|
|||
|
push BX ; and push for call
|
|||
|
mov DX,DS
|
|||
|
mov ES,DX ; set ES for C routine
|
|||
|
C_call int2long ; convert register to long
|
|||
|
mov SP,BP
|
|||
|
or ax,ax
|
|||
|
jnz lt_err ; jump on error
|
|||
|
mov ax,[BP].COUNT+2 ; get high word of long integer
|
|||
|
or ax,ax ; if negative
|
|||
|
js lt_rtn ; return
|
|||
|
|
|||
|
mov SI,[BP].REGSAVE ; reg holding list ptr
|
|||
|
mov BX,[SI].C_page ; BX <= page of list
|
|||
|
cmp byte ptr ptype+[BX],LISTTYPE*2 ; is it a list ?
|
|||
|
jne lt_err ; no, jump
|
|||
|
|
|||
|
mov AX,BX ; AX <= page of list
|
|||
|
mov BX,[SI].C_disp ; BX <= disp of list
|
|||
|
|
|||
|
lt_loop:
|
|||
|
mov CX,[BP].COUNT+2 ; get lsw of long int
|
|||
|
or CX,[BP].COUNT
|
|||
|
jz lt_rtn ; jump if long int = zero
|
|||
|
cmp AX,NIL_PAGE ; end of list?
|
|||
|
je lt_rtn ; yes, return
|
|||
|
LoadPage ES,AX ; ES <= page address of list cell
|
|||
|
mov AL,ES:[BX].cdr_page ; AX <= page # of cdr
|
|||
|
mov BX,ES:[BX].cdr ; BX <= disp of cdr
|
|||
|
sub word ptr [BP].COUNT,1 ; decrement count
|
|||
|
sbb word ptr [BP].COUNT+2,0
|
|||
|
jmp lt_loop ; and loop
|
|||
|
lt_rtn:
|
|||
|
mov byte ptr [SI].C_page,AL ; save page in reg
|
|||
|
mov [SI].C_disp,BX ; save disp in reg
|
|||
|
add SP,BP_SAVE
|
|||
|
pop BP
|
|||
|
pop ES
|
|||
|
jmp next_SP
|
|||
|
|
|||
|
lt_err:
|
|||
|
add SP,BP_SAVE
|
|||
|
pop BP
|
|||
|
pop ES ; restore ES register
|
|||
|
restore <SI> ; and instruction pointer
|
|||
|
xor AX,AX
|
|||
|
mov AL,ES:[SI]-1
|
|||
|
add AX,offset reg0 ; get last operand
|
|||
|
push AX ; and push for call
|
|||
|
xor AX,AX
|
|||
|
mov AL,ES:[SI]-2
|
|||
|
add AX,offset reg0 ; get first operand
|
|||
|
push AX ; and push for call
|
|||
|
|
|||
|
mov BX,offset m_ltail ; load address of message text
|
|||
|
pushm <m_two,BX> ; and push
|
|||
|
C_call set_src_,<SI>,Load_ES
|
|||
|
restore <SI>
|
|||
|
jmp sch_err
|
|||
|
|
|||
|
|
|||
|
car_cdr endp
|
|||
|
|
|||
|
prog ends
|
|||
|
end
|
|||
|
|