Casl语言试题解答(90~93)下

程序员级试题
1993年
试题1
[程序说明]

子程序 UPDATE 每隔一秒被调用一次,届时对存贮单元 HOUR( 时 ),MINUTE( 分 )以及SECOND( 秒 )的当前值予以更新处理。

SECOND 与 MINUTE 均为六十进制, HOUR 为廿四进制。HOUR,MINUTE 和 SECOND 的递加与复零均由公用子程序 ADDONE 进行。

[程序]

标号 操作码 操作数
UPDATE START
PUSH 0,GR1
PUSH 0,GR2
PUSH 0,GR3
LEA GR2, ①
LEA GR3, ②
CALL ADDONE
CALL ADDONE
LEA GR2, ⑥
LEA GR3, ⑦
CALL ADDONE
UPTOK POP GR3
POP GR2
POP GR1
RET
HOUR DC 0
MINUTE DC 0
SECOND DC 0
ADDONE
CPA GR2,0,GR3
JZE ADDOK
LD GR1,0,GR3
LEA GR1,1,GR1
ADDOK   ST GR1,0,GR3
RET
END

分析

本题给出的子程序UPDATE是每隔一秒对三个变量HOUR(时),MINUTE(分)和SECOND(秒)作一次更新,对它们的递加或复零均由子程序ADDONE完成。显然,子程序ADDONE应能适应不同进位的复零和对不同变量的递加。

在子程序UPDATE中,两处调用ADDONE的CALL指令之前均有对GR2和GR3置数的指令LEA,这说明GR2和GR3是用作传递参数的,进一步搞清楚它们中的值的含义是解答本题的关键所在。

分析子程序ADDONE中的比较指令和它之后的指令组可知,GR2中存放的是一个数值,GR3中存放的是一个存贮单元地址;同时,可知在满足

(GR2)≠((GR3))
条件时,GR3所指单元被累加1,完成的是递加功能;在不满足上面条件时,把GR1中的值送入GR3所指的存贮单元,完成的是复零功能,此时GR1中的值应为0,才能实现复零要求,因此⑧的解答为

LEA GR1,0
由上分析可推得,GR3中应是存放秒或分或时的存贮单元地址,GR2中应是59(处理秒或分)或23(处理小时)。

子程序UPDATE中的第一次调用ADDONE是对秒的处理,在此CALL指令之前的空格①和②应填入

59和SECOND
以实现对秒的递加或复零。当调用返回后,只有在秒被复零时,需进一步对分进行递加或复零,所以子程序ADDONE执行结束后,应给出一个状态,以示这次调用完成的是递加还是复零。寻找这个状态,是解答本题的另一个关键。

进一步分析子程序ADDONE中的指令,可得到复零时GR1值为0,而递加时GR1值为非0,即用GRl的值可以区分子程序ADDONE所完成的不同功能,而GR1中值的不同情况,在返回调用处时,隐含在标志器FR中,这可以认为子程序ADDONE传递执行结果的一种方式和途径。由此可得,③和⑤的解答均为

JNZ UPTOK
即不再需要进一步对分或时作处理。⑥和⑦的解答应

23和HOUR
为对时处理送参数。剩下的空格④似乎不太容易填,因为在它之后的调用是对分的处理,应在GR2置59,GR3中置MINUTE,而④处只能填一条指令。我们再分析子程序ADDONE的执行情况,它执行结束后GR2中的值是不变的,所以④处只要填入置GR3值的指令,即

LEA GR3,MINUTE
到此,本题已解答完毕。从分析和解答的过程中,可得到如下启示,即在解题过程中正确、完整地去分析一个子程序,包括它所需参数的存放位置及值的含义、完成的操作和执行结果的传递方式等,对解题是很有帮助的。
解答 ① 59 ② SECOND ③ JNZ UPTO K④ LEA GR3,MINUTE

⑤ JNZ UPTOK ⑥ 23 ⑦ HOUR ⑧ LEA GR1,0


试题2
[程序说明]

子程序 ENCRPT 用来对给定字符串进行加密处理。

子程序使用密钥字符串与待加密字符串按顺序逐个字符进行异或操作以实现加密处理。在加密过程中如已经使用了密钥字符串的最后一个字符,则再从密钥字符串的第一个字符起重复取用,待加密字符串的全部字符处理完毕后,子程序返回其调用程序。

子程序所需的全部参数( 待加密字符串长度及字符串首址,密钥字符串长度及字符串首址 )均通过栈来传递。以下是一个调用实例:

:

:

LD GRl,CHRL
PUSH 0,GRl
PUSH CHRS
LD GRl,KEYL
PUSH 0,GRl
PUSH KEYS
CALL ENCRPT
LEA GR4,4,GR4
: :

其中标号为 CHRL 的存贮单元内是待加密字符串的长度,从标号为 CHRS 的存贮单元起顺序存放待加密字符;标号为 KEYL 的存贮单元内是密钥字符串的长度,从标号为 KEYS 的存贮单元起顺序存放密钥字符串的字符。
[程序]

标号 操作码 操作数
ENCRPT START
PUSH 0,GR1
PUSH 0,GR2
PUSH 0,GR3
LEA GR0,0
CPA GR0,5,GR4
JPZ ENDENC
CPA  GR0,7,GR4
JPZ ENDENC
__①__
RESET LD GRl, __②__
LD GR2, __③__
IFEND LD GR0,7,GR4
SUB GR0,NUMl
JMI ENDENC
ST __④__
GOON LD GR0,0,GR3
EOR GR0,0,GR1
ST GR0,0,GR3
LEA GRl,1,GR1
__⑤__
LEA GR2,-1,GR2
__⑥__
JMP RESET
ENDENC POP GR3
POP GR2
POP GR1
RET
NUMl DC 1
END

分析

阅读程序说明可知,本题给出的子程序ENCRPT是对给定的字符串进行加密处理,加密的算法是简单的,而正确引用在栈中提供的诸参数是解答本题的关键。

从给出的调用实例和进入子程序执行进栈指令后,栈中的内容见下图。

栈顶→

(GR3)

(GR2)

(GR1)

返 回 迹

密钥字符串首址

密钥字符串长度

待加密字符串首址

待加密字符串长度

下面我们通过分析程序的结构,根据填空前后指令的功能并结合栈中的内容,推出程序中各部分在实现加密过程中的作用,从而逐步求得解答。

程序一开始是判断密钥字符串长度和待加密字符串长度,若两者有一为0,就结束程序执行;①、②和③三个空格估计是置初值;标号IFEND起的三条指令是对待加密字符串长度减1,在小于。时结束程序执行,表示已将待加密字符串中的每个字符作了加密处理,在大于和等于。的情况下,应继续去加密下一字符,同时应将被减1后的长度保留在长度单元中,所以在④处可填入 GR0,7,GR4
从标号GOON起的四条指令是实现

((GR3))Å((GR1))→(GR3)

(GR1)+1→GR1
按程序说明中的加密算法,可推出寄存器GR3所指向的是待加密字符位置,寄存器GR1所指向的是密钥字符位置,当一个字符被加密后,GR1和GR3都应增加1,让他们指向下一字符,在这里只有对GR1加1的指令,而未给出对GR3加1的指令,所以⑤处应有一条

LEA GR3,1,GR3
指令,使GR3指向下一字符;同时,在开始加密前GR1和GR3应分别指向密钥字符串和待加密字符串之首,分析①,②和③三处已给出的操作码与寄存器,可得②处应填入

4,GR4
完成置GRI的初值,而在③处不能对GR3置初值,故①处应填入

LD GR3,6,GR4
实现置GR3的初值。⑧处的指令是对GR2赋值,结合⑤,⑥之间的GR2减1指令和控制待加密字符串长度在IFEND处完成,可推出GR2是用来控制密钥字符串长度的,所以在⑧处应将密钥字符串长度取到GR2,得③的解答为

5,GR4
最后解答空格⑥,注意到⑥之后的无条件转向RESET指令,它表示此时密钥字符已用完,转去对GRl和GR2重新置初值,再从密钥字符串的第一字符起重复使用;而⑥之前是控制密钥字符串长度的寄存器GR2减1指令,所以⑥处应是一条控制密钥字符是否被用完的指令。在初值为长度,先使用后减1的情况下,应该用非零转指令控制密钥字符是否被用完,故⑥的解答为

JNZ IFEND
转去判断待加密字符是否还有。
解答① LD GR3,6,GR4 ② 4,GR4 ③ 5,GR4

④ GR0,7,GR4 ⑤ LEA GR3,1,GR3 ⑥ JNZ IFEND
 

试题3
[程序说明]

子程序NPUT将正整数N嵌入一存贮字WORD的第P位起的W位中,并使其余各位保持不变。

主程序在GRI中给出存放子程序所需参数的起始地址。参数的存放形式,如下图所示。

(GR1)+0

+1

+1
+3
WORD
P
W
N
0≤P≤15
0%W≤16一P
0≤N≤2’一1

例:

GR1)+0
+1
+2
+3
WORD
7
5
21


7
WORD

1 0 1 0 1 0 1 0 l 0 1 0 1 0 1 0

调用子程序 NPUT 后 WORD 变成

7
WORD

1 0 1 0 1 0 1 1 0 1 0 1 1 0 1 0

子程序返回时,若 GR0 的值为 0,则表示子程序已经正常执行。若 GR0 的值为 1,则表示参数不合理,子程序异常退出。进入子程序时,已确保 P≥0,W>0 。程序中工作单元 MASKEP 和 MASKCP 分别有如下形式的数值:

|←W→|
MASKEP

1........1 0...0

P
MASKEP

1....l0...0 1...1

|←W→|

[程序]

标号 操作码 操作数
NPUT START
PUSH 0,GRl
PUSH 0,GR2
PUSH 0,GR3
LD GR2,2,GR1
LD GR0,FULLB
__①__
ST GR0,MASKEP
EOR GR0,FULLB
LEA GR3,16
SUB GR3,2,GRl
__②__
JMI ERROR
SLL GR0,0,GR3
__③__
ST GR0,MASKCP
LD GR0,3,GR1
__④__
JNZ ERROR
LD GR2,0,GR1
__⑤__
AND GR0,MASKCP
LD GR1,3,GR1
SLL GR1, __⑥__
ST GR1,TEMP
OR __⑦__
ST GR0,0,GR2
LEA GR0,0
FIN POP GR3
POP GR2
POP GR1
RET
ERROR LEA GR0,1
JMP FIN
LB DC #FFFF
MASKEP DS 1
MASKCP DS 1
TEMP DS 1
END

分析

本题是一个二进位移位和装配性的试题,类似的试题在历年试题中出现过,解答这种类型的试题,首先按照题意考虑实现算法,然而仔细阅读程序,分析空格前后指令组在实现算法过程中的功能和所起作用,就能逐步求得解答。

将正整数N嵌入一存贮字WORD的第P位起的W位中,并使WORD的其余位保持不变,可分三步实现。首先将WORD的内容加工成如图1所示,即将WORD的第P位起的W位置成0,而其余位保持原值;再将正整N(0≤N≤2W-1)加工成如图2所示,即将数N左移16-W-P位;最后将Ⅰ与Ⅱ逻辑加就实现正整数N嵌入WORD的P位起的W中。

根据程序说明中给出的工作单元MASKCP内的数值,把WORD加工成Ⅰ,可通过下面的操作实现:

(MASKCP)∧(WORD)

把N加工成Ⅱ,只要将N左移16-W-P位即可。

下面我们按照上述算法步骤,分析和阅读程序,逐个求得解答。

程序的前半部是在存贮字MASKEP和MASKCP中形成程序说明中给出的数值,为实现问题的算法作准备。要得到MASKEP中的数值,只要将全1逻辑左移W位即可,故①处应填

SLL GR0,0,GR2
要得到MASKCP,可用如下操作实现:

((MASKEP)Å(FULLB))←16-w-pÅ(FULLB)

其中FULLB为全1。按此操作步骤,对照③处前后的指令可知,在③之前的GR0中是数值

(MASKEP)Å(FULLB)
将它左移(GR3)位,执行⑧处的指令后将GR0送入MASKCP,这里的GR0应是最终结果,所以③处应填

EOR GR0,FULLB
而GR3的值应是16-W-P。注意到空格②之前的减法指令执行后GR3中的值为16-W,从而可得②的解答为

SUB GR3,1,GR1
有了MASKCP中的数值,要将woRD的内容加工成I,只要逻辑乘即可。在程序后半部的⑤处之前是将地址WORD取入GR2,⑤处之后是GR0内容与MASKCP内容逻辑乘,显然GR0中应是存贮字WORD的内容,即⑤处应填

LD GR0,0,GR2
将WORD内容取入GR0。程序最后处的⑥与⑦两处可分别填入

0,GR3

GR0,TEMP
完成对N的移动和最终的合成。剩下空格④的解答,可从它之后的非零转指令去向和它之前将N取入GR0的指令推出,这几条指令是检查N的正确性,即是否满足下列不等式:

0≤N≤2W-1
用一条指令检验两个条件似乎有点困难。十个大于2W-1或小于0的数,用二进位在一个16位存贮字中表示,在最高位至16-W中一定有非零的位,所以④处可填

AND GR0,MASKEP
实现对N范围正确检验。
解答 ①SLL GR0,0,GR2 ②SUB GR3,1,GR1 ③EOR GR0,FULLB ④AND GR0,MASKEP

⑤LD GR0,0,GR2 ⑥0,GR3 ⑦GR0,TEMP

高级程序员级试题

1990年

[程序说明]

本程序完成两个 4 位十进制数相加,并输出两数之和。

例: 输入 '5794+6438'

     输出 '12232'

(1)必须按上述要求输入,否则输出 'INPUT ERROR' 信息,并重新输入。

(2)从低位开始,逐位进行十进制相加。

(3)若输入长度为 0 时,本程序结束。
[问题]

在程序中的 ①~⑦ 处各填入一条正确指令,以完成此程序。除非必要,标号栏不要填写。
[程序]

标号 指令码 操作数
START
BEGIN ST GR4,SPW
RETRY IN INBUF,LENG1
LEA GR1,0
CPA GR1,LENG1
JZE HALT
LEA GR2,9
CPA GR2,LENG1
JNZ ERROR
LEA GR3,4
__①__
CPL GR0,SING
JZE PASS1
ERROR OUT INERR,LENG2
JMP RETRY
PASS1 LD GR1,SM
ST GR1,INBUF,GR3
LEA GR1,0
LOOPl LD GR3,INBUF,GR1
LEA GR1,1,GR1
CPL GR3,SM
JMI ERROR
CPA GR3,LM
JPZ ERROR
AND GR3,BCD
PUSH 0,GR3
__②__
JNZ LOOP1
ST GR2,CY
LEA GRl,4
__③__
ADD GR3, __④__
ADD GR3,CY
CPA GR3,TEN
JMI LABl
ADD GR3,SIX
AND GR3,BCD
__⑤__
JMP LAB2
LAB1 LEA GR0,0
LAB2 ST GR0,CY
OR GR3,SM
ST GR3,OUTBUF,GRl
__⑥__
JNZ LOOP2
OR GR0,SM
__⑦__
OUT OUTBUF,LENG3
JMP RETRY
HALT LD GR4,SPW
EXIT
SPW DS 1
INBUF DS 80
LENG1 DS 1
INERR DC 'INPUT ERROR'
LENG2 DC 11
SING DC '+'
SM DC '0'
LM DC ':'
BCD DC #000F
CY DS 1
TEN DC 10
SIX DC 6
OUTBUF DS 5
LENG3 DC 5
END

分析

阅读程序说明和粗略阅读程序,了解题意和分析程序的结构,可以预测到本程序实现四个4位十进制数相加并输出两数之和的过程,大致可分为以下几步:

(1)检查输入串的合法性,包括长度和每一个字符。

(2)将被加数与加数中的每一个字符的ASCII码转换成BCD码。

(3)从低位开始,逐位进行十进制加法,在相加的过程中要加上低位来的进位和产生向高位的进位。

(4)将和的每一位数转换成ASCII码后输出两数之和。

按照上述步骤,仔细推敲程序中填空位置前后指令组的功能和作用,就能较容易求得解答。

显然可知,从标号BEGIN开始的八条指令是检查输入串的长度是否为9。考察JNZ ERROR之后的八条指令可得:若(GR0)=‘+’时,就将INBUF+4置成‘0’,否则出错。因此,它是检查输入串的第五个字符是否为‘+’符,即GR0中应是输入串中的第五个字符,所以①的解答为

LD GR0,INBUF,GR3
在这里,不仅校验了在输入串的指定位置上出现‘+’符;同时,也校验了被加数与加数的位数均是4,将INBUF+4置成‘0’,为以后统一检查输入缓冲区中字符的合法性提供了方便。

从LEA GR1,0至JNZ LOOP1十一条指令构成一个循环,它检查输入缓冲区中的每一个字符是否为‘0’~‘9’。显然,②应该是一条控制循环的计数器修改指令,它可以 是

LEA GR2,-1,GR2 或 LEA GR3,-9,GR1
但结合JNZ LOOP1之后的ST GR2,CY指令——进位标志器置初态0,会发现将9送入 CY是不适宜的,从而②的正确解答是

LEA GR2,-1,GR2

在此循环内,不仅检查了被加数与加数的合法性,同时把它们的每一个字符转换成BCD码,并按输入次序压入栈中。由此可以推测在以后的程序中进行逐位十进制相加时,必须从栈中取出各位制数。若输入串为

a4a3a2a1+b4b3b2b1
经上述处理后,栈中的内容如下图所示。

   

……

a4 a3 a2 a1 0 b4 b3 b2 b1  

栈底

(GR4)+5

(GR4)

由此可见,被加数的各位与加数的各位,在栈中的存贮位置的间隔是5。

LEA GR1,-4至JNZ LOOP2十六条指令组成程序中的另一个循环,它是实现两个四位十进制数逐位相加,并把和的每一位数值转换成相应的ASCII码后存入输出缓冲区。

分析下述四条指令:

ADD GR3,④

ADD GR3,CY

CPA GR3,TEN
可推测,它们是用来实现两个4位十进数中的对应位相加,再加上低位来的进位,并判断是否产生向高位的进位。因此,指令③应是将被加数中的1位十进数取入GR3,④应是与被加数相对应的加数中的1位十进数的存贮位置。结合被加数和加数的对应位之间在栈中的间隔距离,就可以得到③和④的初步解答为

POP GR3

5,GR4
注意到执行退栈指令,栈指针会自动加1,所以应将解答④中的5改为4。寄存器GR1的初态为4,是存放加法和的各位十进数的存贮位置指针,所以⑥的解答应为

LEA GR1,-1,GR1
而JNZ LOOP2中的转移位置LOOP2应是指令③的标号,因此③和④的正确解答应为

LOOP2 POP GR3

4,GR4

当2位十进数的和大于10时,要产生进位,所以⑤的解答为

LEA GR0,1
当LOOP2循环结束后,两个4位十进数之和的最高位进位存放在GR0中,应将它存入输出缓冲区的OUTBUF内,所以⑦的解答为

ST GR0,OUTBUF
解答 ①LD GR0,INBUF,GR3 ②LEA GR2,1,GR2 ③LOOP2 POP,GR3 ④4,GR4

⑤LEA GR0,1 ⑥LEA GRl,-1,GR1 ⑦ST GR0,OUTBUF

1991年试题

[程序说明]

本子程序将存贮字 A 中的第 a 位起的 n 位二进位,搬至存贮字 B 的第 b 位起的 n 位中。

(1)主程序在 GR1 中给出子程序所需参数的起始地址。

(2)子程序所需参数个数和含义如下图所示。

GR1+0  A    

↓A

 
+1  a A
     
+2  n   |← n →|
+3  B B
     
+4  b    

B↑

 

(3)0≤a≤15; 0≤b≤15; 1≤n≤16; a+n≤16; b+n≤16。

(4)存贮字B中,除b开始的n位外的其它二进位应保持原值。
[问题]

在程序中的①~⑧处各填入一条正确的指令,以完成此程序。除非必要,标号栏不要填写。
[程序]

MOVBIT START
LD GR2,2,GR1 

在SAVE1中形成

__①__
11…1 00…………0
__②__

n个

ST GR2,SAVE1
LD GR2,1,GR1
__③__
LD GR2,0,GRl
AND GR0,0,GR2
LD GR2,4,GR1
CPA GR2,1,GR1
__④__
LD GR2,l,GRl
SUB GR2,4,GRl
__⑤__
JMP  SHFTE
SHFTR SUB GR2,1,GRl
__⑥__
SHFTE ST GR0,SAVE2
LD GR2,SAVE1
LD GR3,4,GR1
__⑦__
__⑧__
LD GR3,3,GR1
AND GR2,0,GR3
OR GR2,SAVE2
ST GR2,0,GR3
RET
C8000 DC #8000
CFFFF DC #FFFF
SAVE1 DS 1
SAVE2 DS 1
END

分析

阅读程序说明和粗略阅读程序,了解题意和分析程序的结构,要将存贮字A中的第a位起的n位二进数搬至存贮字B的第b位起的n位中,可以分如下几步来实现:

(1)先设法取得A中的第a位起的n位,即得到如图a所示的16位二进数Ⅰ。其 中x x…。表示A中的第a位起的n位二进数。然后,将Ⅰ左移a-b位(当a>b时)或右移b-a位(当a≤b时),得到Ⅱ(见图b)。

(2)将存贮字B的第b位起的n位变成0,而其他位保持原值,即如Ⅲ(见图c)所示。

(3)把Ⅱ和Ⅲ逻辑加送入B,就实现了试题的要求。

按照上述步骤,仔细推敲程序中填空位置前后指令组的功能和作用,就能较快地求得解答。

若在SAVEl中已有如图d所示形式的16位二进数Ⅳ。要从A中得到Ⅰ,只要将Ⅲ右移a位后同存贮字A中的内容逻辑乘即可。在程序说明中已指出,GR1中存放子程序所需参数A,a,n,B,b的起始地址,注意到③之后的两条指令是完成(A)∧(GR0),而③之 前的GR2中有a,因此GR0中一定是如图d所示形式的二进制数。它是Ⅳ逻辑右移a 位的结果,故⑧处应填入

SRL GR0,0,GR2

要在SAVEl中有Ⅳ,只要将215算术右移n-l位,故①和②处应分别填入

LD GR0,C8000

SRA GR0,-1,GR2

当得到Ⅰ后(在GR0中),就要根据a,b的大小进行左移或右移,将Ⅰ调整成Ⅱ。注意到 ④之前的两条指令是比较b和a的大小,而④之后的两条指令是a-b存于GR2中,这是在b小于a的情况要做的。由此可得,④处应是大于等于转指令,且是转到执行b-a的指令处
(标号为SHFTR),⑤应是将Ⅰ左移a-b位的指令,故④和⑤两处应分别填入

JPZ SHFTR

SLL GR0,0,GR2

在⑥处应填入

SRL GR0,0,GR2
将Ⅰ右移b-a位。移位后的结果为Ⅱ,保存在SAVE2中。

要将存贮宇B中的内容变成Ⅲ,只要先把SAVE1中的内容逻辑右移b位同全1按位加,再将按位加结果逻辑乘存贮字B中的内容即可。分析⑦和⑧前后指令的功能,就可知⑦和⑧处应填入

SRL GR2,0,GR3

EOR GR2,CFFFF
解答 ①LD GR0,C8000 ②SRA GR0,-1,GR2

⑧SRL GR0,0,GR2 ④JPZ SHFTR

⑤SLL GR0,0,GR2 ⑥SRL GR0,0,GR2

⑦SRL GR2,0,GR3 ⑧EOR GR2,CFFF

1992年试题
[程序说明]

本程序根据输入的姓名(字符串),在已有的线性表中查找其相应的通信地址(字符串),并予以输出。

标号为DATPTR的存贮字存放着线性表第一个结点的地址。结点的数据结构定义如下:

 

第K个结点
+0   指向第K+1个结点
+1   存放姓名字符串长度
+2   存放通信地址字符串长度
+3   自此连续存放姓名和通信地址
… 

最后一个结点的指针字段为空指针( 内容为 0 )。
[程序]

START BEGIN
OTlONG DS 1
OTTEXT DS 80
NOlONG DC 10
NOTEXT DC 'NOT FONUD.'
INTEXT DS 80
INLONG DS 1
DATPTR DC FIRST
BEGIN IN INTEXT,INLONG
LEA GR0,0
CPA GR0,INLONG
JZE ENDSCH
LEA GR3,DATPTR
NXTMEM __①__
__②__
JZE NOTFND
LD GR0,1,GR3
CPA GR0,INLONG
JNZ NXTMEM
__③__
LEA GR2,INTEXT
CALL CMPSTR
__④__
LD GR0,2,GR3
ST GR0,OTlONG
__⑤__
__⑥__
LEA GR2,OTTEXT
CAlL CPYSTR
OUT OTTEXT,OTLONG
JMP BEGIN
NOTFND OUT NOTEXT,NOLONG
JMP BEGIN
ENDSCH EXIT
CMPSTR PUSH 0,GR3
CMPNXT LD GR3,0,GR1
CPL GR3,0,GR2
JNZ CMPEND
LEA GR1,1,GR1
LEA GR2,1,GR2
SUB GR0,CONST1
JNZ CMPNXT
CMPEND POP GR3
RET
CONSTl DC 1
CPYSTR PUSH 0,GR3
CPYNXT LD GR3,0,GR1
ST GR3,0,GR2
LEA GR1,1,GR1
LEA GR2,1,GR2
SUB GR0,ONE
JNZ CPYNXT
POP GR3
RET
ONE DC 1
END

分析

通过阅读程序说明和分析程序的结构,可明白以下几点:

(1)本程序是根据输入的姓名(字符串),在勾链线性表中查找相应的地址并予以输出。

(2)勾链表的首结点由DATPTR指示。每个结点内存贮着指向下—结点的指针、姓名字符串及它的长度、通信地址及它的长度,它们在存贮区域内的相对位置可由下图表示。

0    指向第K+1个结点
1 N1  姓名字符串长度
2 N2  通信地址字符串长度

3

...

N1个存贮字
存放姓名
 
N1+3 N2个存贮字
存放通信地址
 

(3)整个程序由两个子程序和主程序组成,在子程序中没有要填空的指令。

(4)子程序CMPSTR的功能是字符串比较。它要求在GR1和GR2中存放被比较的两个字符串的首位置,GR0内存放被比较字符串长度,比较结果反映在FR中,FR内的值为01表示两个字符相同,00或10表示两个字符串不相同。

(5)子程序CPYSTR的功能是字符串复制。它将长度为(GRO)、存放在首位置且由GR1指示的字符串,复制到首位置由GR2指示的存贮区域内。

有了这些信息,再仔细阅读分析主程序中的指令,结合勾链表查找算法,就可逐步求得解答。

程序一开始将要查找的姓名字符串输入在INTEXT开始的存贮区域内,它的长度放在INLONG中。

接下来是一个NXTMEM循环,在此循环中控制循环结束的条件是,输入字符申的长度与由GR3指示的结点姓名字符串长度相等,否则继续循环。显然,要改变结点再比较才有意义,否则要死循环。在框①之前,将ATPTR送GR3,在框②之后的转移指令表示找不到,即已到最后一个空结点,所以①和②两条指令一定是实现结点指针的移动,它可用如下两条指令未完成:

①LD GR3,0,GR3

②LEA GR3,0,GR3

当输入的姓名字符串长度与某一结点中的姓名字符串长度相等时,这两个字符串才有可能相同,要比较两个字符串是否相同,可调用子程序CMPSTR,只要在调用前将GR0,GR1,GR2的初态置好,所以框③的解答为

LEA GR1,3,GR3
将结点中的存放姓名字符串存区的首位置送GR1。

在框④前的调用字符串比较子程序,返回时比较结果反映在FR中,所以框④是一条转移指令,用来区分比较的结果,考察框⑥之后的指令是复制字符串和输出字符串,这是比较结果为相同时要作的处理,因此框④的转移指令为

JNZ NXTMEM

⑤和⑥两框显然是为调用子程序CPYSTR传递参数的,注意⑤和⑥的前后指令已将GR0和GR2置好,所以⑤,⑥的解答为

LEA GR1,3,GR3

ADD GR1,1,GR3
将查到的通信地址字符串存区首址送GR1。
解答 ①LD GR3,0,GR3 ②LEA GR3,0,GR3 ③LEA GR1,3,GR3

④JNZ NXTMEM ⑤LEA GR1,3,GR3 ⑥ADD GR1,1,GR3

1993年

[程序说明]

子程序 MOVE 是将地址为 A 开始的 N 个存贮单元移动到地址为 B 开始的 N 个存贮单元中,对于两个区域互相重叠的情况也能正确处理。

主程序在 GR1 中给出存放子程序所需参数的起始地址,参数的存放形式如下图所示。

(GR1)+0

A

+1

B

+2

N

[程序]

MOVE  START
LD GR2,1,GR1
LD GR3,0,GRl
CPL GR3,1,GRl
JZE ENDMOV
__①__
__②__
JMP SAVE
LT __③__
LEA GR3,__④__
__⑤__
LEA GR2,__⑥__
__⑦__
SAVE ST GR0,WORK
LD GRl,2,GRl
LOOP LD GR0,0,GR3
ST GR0,0,GR2
ADD GR2,WORK
ADD GR3,WORK
LEA GR1,-1,GR1
JNZ LOOP
ENDMOV RET
WORK DS 1
END

分析

阅读程序说明可知,本题是一个成组传送子程序,将地址为A开始的N个存贮单元移动到地址为B开始的N个存贮单元中。正确处理两个存贮区域互相重叠的情况,是解答本题的关键。

在源存区和目的存区有重叠时,必须分三种情况分别处理。若A大于B时,应作顺向传送,即

(A+i)→ B+i (i=0,1,…,N-1)
若A小于B时,应作逆向传送,即

(A+i)→B+i (i=N-1,…,1,0)

显然在A等于B时,可不作移动。另外,在调用子程序MOVE时,主程序在寄存器中给出存放子程序所需参数的起始地址,在子程序需要多个参数的情况下,这是经常采用的一种参数传递方式,在历年的汇编语言试题中已出现过多次,所以掌握好这种参数传递方式时,子程序取得参数的方法,对解答试题是很有帮助的。
按照上述三种情况,阅读和分析程序的结构,推敲填空位置前后指令组的功能和作用,就能较快地求得解答。

子程序MOVE开始的几条指令是将A和B分别取至GR3和GR2,然后比较它们的大小,在相等时就立即返回主程序(此时不必作移动)。在空格①和②之后是无条件转向SAVE,因此可推测①和②处是区分A和B的大小。由于从SAVE开始到程序末尾无空格要填,所以我们可先去分析和理解这段指令的功能。在这段指令中有一个LOOP循环,GRI是循环计数器,初态为N每次减1,显然是控制N个存贮单元的传送;在循环体内,将GR3所指单元中的内容传送到GR2所指的单元中,然后GR3和GR2均增加WORK(初态是GR0中的值)。按顺向和逆向传送的不同要求可知,在顺向传送(A大于B)时,GR3和GR2的初值应是A和B,WORK的值应为1;而逆向传送时,GR3和GR2的初值应是A+N-1和B+N-1,WORK的值应为-1。这些初态和常数应在转入SAVE前置好,才可做到正确传送。分析了LOOP循环的功能和它要求的初值,可推断在SAVE之前的指令一定是根据A,B比较结果,将GR3,GR2和GR0的初态置好,然后进入SAVE,完成移动。

注意到程序一开始时GR3和GR2中的值和标号LT开始的指令中有改变GR3和GR2中值的操作码,就可推测LT起的该段指令组是为逆向传送作初态准备;LT之前的指令为顺向传送作初态准备,并且一定有

JMI LT
指令(空格①或②),即A小于B转向LT,置GR3的初态为A+N-1、GR2的初态为A+N-1和GR0的值为-1。从空格④和⑥之前的操作码和寄存器,就可得到③至⑦五个空格的如下两个等价的解答:

LEA GR0,-1

-1,GR3

ADD GR3,2,GR1

-1,GR2

ADD GR2,2,GR1

ADD GR3,2,GR1

-1,GR3

ADD GR2,2,GR1

-1,GR2

LEA GR0,-1

从而可得①,②的解答为

JMI LT

LEA GR0,l

注意这两条指令的次序不能颠倒,因为LEA操作要改变标志寄存器FR的状态。
解答①JMI LT ②LEA GR0,1 ③ADD GR3,2,GR1 ④-1,GR3

⑤ADD GR2,2,GRI ⑥-1,GR2 ⑦LEA GR0,-1

老顽童整理2003年8月