📄 iters.asm
字号:
; Iterator example.
;
; Roughly corresponds to the example in Ghezzi & Jazayeri's
; "Programming Language Concepts" text.
;
; Randall Hyde
;
;
; This program demonstrates an implementation of:
;
; l := 0;
; foreach i in range(1,3) do
; foreach j in iter2() do
; writeln(i, ',', j, ',', l):
;
;
; iterator range(start,stop):integer;
; begin
;
; while start <= stop do begin
;
; yield start;
; start := start+1;
; end;
; end;
;
; iterator iter2:integer;
; var k:integer;
; begin
;
; foreach k in iter3 do
; yield k;
; end;
;
; iterator iter3:integer;
; begin
;
; l := l + 1;
; yield 1;
; l := l + 1;
; yield 2;
; l := l + 1;
; yield 0;
; end;
;
;
; This code will print:
;
; 1, 1, 1
; 1, 2, 2
; 1, 0, 3
; 2, 1, 4
; 2, 2, 5
; 2, 0, 6
; 3, 1, 7
; 3, 2, 8
; 3, 0, 9
.xlist
include stdlib.a
includelib stdlib.lib
.list
.286 ;Allow extra adrs modes.
dseg segment para stack 'data'
; Put the stack in the data segment so we can use the small memory model
; to simplify addressing:
stk byte 1024 dup ('stack')
EndStk word 0
dseg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg, ss:dseg
; Here's the structure of a resume frame. Note that this structure isn't
; actually used in this code. It is only provided to show you what data
; is sitting on the stack when Yield builds a resume frame.
RsmFrm struct
ResumeAdrs word ?
IteratorLink word ?
RsmFrm ends
; The following macro builds a resume frame and the returns to the caller
; of an iterator. It assumes that the iterator and whoever called the
; iterator have the standard activation record defined above and that we
; are building the standard resume frame described above.
;
; This code wipes out the DX register. Whoever calls the iterator cannot
; count on DX being preserved, likewise, the iterator cannot count on DX
; being preserved across a yield. Presumably, the iterator returns its
; value in AX.
ActRec struct
DynamicLink word ? ;Saved BP value.
YieldAdrs word ? ;Return Adrs for proc.
StaticLink word ? ;Static link for proc.
ActRec ends
AR equ [bp].ActRec
Yield macro
mov dx, AR.YieldAdrs ;Place to yield back to.
push bp ;Save Iterator link
mov bp, AR.DynamicLink ;Get ptr to caller's A.R.
call dx ;Push resume address and rtn.
pop bp ;Restore ptr to our A. R.
endm
; Range(start, stop) - Yields start..stop and then fails.
; The following structure defines the activation record for Range:
rngAR struct
DynamicLink word ? ;Saved BP value.
YieldAdrs word ? ;Return Adrs for proc.
StaticLink word ? ;Static link for proc.
FailAdrs word ? ;Go here when we fail
Stop word ? ;Stop parameter
Start word ? ;Start parameter
rngAR ends
rAR equ [bp].rngAR
Range proc
push bp
mov bp, sp
; While start <= stop, yield start:
WhlStartLEStop: mov ax, rAR.Start ;Also puts return value
cmp ax, rAR.Stop ; in AX.
jnle RangeFail
yield
inc rAR.Start
jmp WhlStartLEStop
RangeFail: pop bp ;Restore Dynamic Link.
add sp, 4 ;Skip ret adrs and S.L.
ret 4 ;Return through fail address.
Range endp
; Iter2- Just calls iter3() and returns whatever value it generates.
;
; Note: Since iter2 and iter3 are at the same lex level, the static link
; passed to iter3 must be the same as the static link passed to iter2.
; This is why the "push [bp]" instruction appears below (as opposed to the
; "push bp" instruction which appears in the calls to Range and iter2).
; Keep in mind, Range and iter2 are only called from main and bp contains
; the static link at that point. This is not true when iter2 calls iter3.
iter2 proc
push bp
mov bp, sp
push offset i3Fail ;Failure address.
push [bp] ;Static link is link to main.
call iter3
yield ;Return value returned by iter3
ret ;Resume Iter3.
i3Fail: pop bp ;Restore Dynamic Link.
add sp, 4 ;Skip return address & S.L.
ret ;Return through fail address.
iter2 endp
; Iter3() simply yields the values 1, 2, and 0:
iter3 proc
push bp
mov bp, sp
mov bx, AR.StaticLink ;Point BX at main's AR.
inc word ptr [bx-6] ;Increment L in main.
mov ax, 1
yield
mov bx, AR.StaticLink
inc word ptr [bx-6]
mov ax, 2
yield
mov bx, AR.StaticLink
inc word ptr [bx-6]
mov ax, 0
yield
pop bp ;Restore Dynamic Link.
add sp, 4 ;Skip return address & S.L.
ret ;Return through fail address.
iter3 endp
; Main's local variables are allocated on the stack in order to justify
; the use of static links.
i equ [bp-2]
j equ [bp-4]
l equ [bp-6]
Main proc
mov ax, dseg
mov ds, ax
mov es, ax
mov ss, ax
mov sp, offset EndStk
; Allocate storage for i, j, and l on the stack:
mov bp, sp
sub sp, 6
meminit
mov word ptr l, 0 ;Initialize l.
; foreach i in range(1,3) do:
push 1 ;Parameters.
push 3
push offset iFail ;Failure address.
push bp ;Static link points at our AR.
call Range
; Yield from range comes here. The label is for your benefit.
RangeYield: mov i, ax ;Save away loop control value.
; foreach j in iter2 do:
push offset jfail ;Failure address.
push bp ;Static link points at our AR.
call iter2
; Yield from iter2 comes here:
iter2Yield: mov j, ax
mov ax, i
puti
print
byte ", ",0
mov ax, j
puti
print
byte ", ",0
mov ax, l
puti
putcr
; Restart iter2:
ret ;Resume iterator.
; Restart Range down here:
jFail: ret ;Resume iterator.
; All Done!
iFail: print
byte cr,lf,"All Done!",cr,lf,0
Quit: ExitPgm ;DOS macro to quit program.
Main endp
cseg ends
; zzzzzzseg must be the last segment that gets loaded into memory!
; This is where the heap begins.
zzzzzzseg segment para public 'zzzzzz'
LastBytes db 16 dup (?)
zzzzzzseg ends
end Main
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -