📄 asmcoun1.pas
字号:
Ctrl-O and Ctrl-N. These control codes may be nested. Processing
proceeds identically to that of the ASCII counter, until a Ctrl-O is
found.
When a control code sequence is found, the Sprint counter enters
another loop. The loop processes characters, keeping count of the
depth of control codes, adding one each time a ^O is encountered,
and subtracting one each time a ^N is found. When the count reaches
zero, the control code is terminated and control returns to normal
word-counting loop.
----------------------------------------------------------------------- }
{ -----------------------------------------------------------------------
InitCount - The Sprint counter's InitCount performs the same functions
as the ASCII InitCount, except that a special value is
placed in the look-up table for Ctrl-O to indicate the
start of control-code processing.
----------------------------------------------------------------------- }
procedure SprintCountObj . InitCount;
begin
CountObj . InitCount;
Table [ ^O ] := $FF;
end;
{ -----------------------------------------------------------------------
Count - Count the words in a Sprint file. Comments annotate differences
between this and CountObj.Count.
There are two pieces of code in this procedure which are kind of
tricky. These were designed to speed and simplify processing, but
they'll require some explanation.
------------------------------------------------------------------
Previous char Current char AH AL Need to do
------------------------------------------------------------------
separator separator 01 01 nothing
separator non-separator 01 00 nothing
separator Ctrl-O 01 FF process control code
non-separator separator 00 01 count a word
non-separator non-separator 00 00 nothing
non-separator Ctrl-O 00 FF process control code
------------------------------------------------------------------
This table shows how the main loop must handle different
situations that will occur. The focus of this code is to maximum
speed. Therefore, the codes for the table were carefully chosen so
that the more common "do nothing" situations can be distinguighed
from the others with a single comparison. Once it has been
determined that something must be done, it can be determined without
another comparison.
cmp AL, AH
ja @CountOrControlCode
<...do-nothing processing...>
@CountOrControlCode:
js <...control-code processing...>
<...count a word...>
The other bit of tricky code is in the control code sequence processing
loop. It is necessary to add one to a counter if character number 15
is found, and to subtract one if character 14 is found. Then, the
loop must be terminated if the count has reached zero. This task is
performed by the following code. (BP holds the depth counter.):
sub AL, 14
sub AL, 1
adc BP, 0
sub AL, 1
sbb BP, 0
jz <...loop complete...>
----------------------------------------------------------------------- }
procedure SprintCountObj . Count;
var
TempCount : longint;
begin
InitCount;
asm
cld
mov [ SaveBP ], BP { When it comes time to process a control }
{ code sequence, the depth counter is }
{ stored in BP. The original value of BP }
{ must be restored later when the method }
{ is complete, and also before ReadBlock }
{ is called. }
xor DX, DX
mov DI, DX
mov AX, 0101h
call @CallReadBlock
@ProcessNormalChar:
mov AH, AL
seges lodsb
xlat
@Continue:
cmp AL, AH { See comments above. }
ja @CountOrControlCode
loop @ProcessNormalChar
call @CallReadBlock
jmp @ProcessNormalChar
@CountOrControlCode:
js @ControlCode
add DI, 1 { Count a word. }
adc DX, 0
loop @ProcessNormalChar
call @CallReadBlock
jmp @ProcessNormalChar
@ControlCode:
mov BP, 1 { Process a control code sequence. A }
jmp @EndControlCodeLoop { control sequence begins with ^O and }
{ ends with ^N. Control codes may be }
{ nested. Therefore it is necessary to }
{ keep a depth counter. As ^O's are }
{ processed, the counter will be }
{ incremented. ^N's will decrement the }
{ counter. When the counter reaches }
{ zero, the control code is complete. }
{ The depth counter will be stored in }
{ BP. Since a ^O has already been }
{ found, the counter is set to 1. }
@ProcessControlCodeChar:
seges lodsb { Get next character. }
sub AL, 14 { See comments above. }
sub AL, 1
adc BP, 0
sub AL, 1
sbb BP, 0
jz @ControlCodeDone
@EndControlCodeLoop:
loop @ProcessControlCodeChar { Process next char. }
mov AL, AH { This line is necessary to ensure }
{ correct processing should the }
{ end-of-file already be reached. }
call @CallReadBlock
jmp @ProcessControlCodeChar
@ControlCodeDone:
mov AL, 1 { Return to normal processing as if a }
jmp @Continue { a separator had been found. }
@CallReadBlock:
pushf
push AX
push DX
push DI
push BP { Save the depth counter, and restore BP }
mov BP, [ SaveBP ] { will ReadBlock is called. }
end; { asm }
ReadBlock;
asm
pop BP
pop DI
pop DX
pop AX
popf
mov BX, offset Table
les SI, [ Block ]
mov CX, [ Actual ]
jcxz @EndOfFile
retn
@EndOfFile:
pop CX
cmp AL, 1
jz @Fini
add DI, 1
adc DX, 0
@Fini:
mov BP, [ SaveBP ] { Restore original BP. }
mov [ word ptr TempCount ], DI
mov [ word ptr TempCount + 2 ], DX
end; { asm }
FiniCount;
WordCount := TempCount;
end;
{ -----------------------------------------------------------------------
AmiPro control code sequences begin with '<', followed by one of '@',
'+' or '-'. The sequence terminates with a '>'. AmiCountObj.Count
processes characters the same as CountObj.Count except that it checks
each character to see if it is a '<'. When a '<' is encountered,
another character is read and checked against '@', '+' and '-'. If
one of these is found, Count enters a loop looking for '>'.
----------------------------------------------------------------------- }
procedure AmiCountObj . Count;
var
TempCount : longint;
begin
InitCount;
asm
cld
xor DX, DX
mov DI, DX
mov AX, 0101h
call @CallReadBlock
@ProcessNormalChar:
mov AH, AL
seges lodsb
cmp AL, '<' { Check to see if character is '<'. If }
jz @PerhapsControlCode { it is, a control code sequence may be }
{ beginning. }
@Continue:
xlat
cmp AX, 0001h
jz @CountWord
loop @ProcessNormalChar
call @CallReadBlock
jmp @ProcessNormalChar
@CountWord:
add DI, 1
adc DX, 0
loop @ProcessNormalChar
call @CallReadBlock
jmp @ProcessNormalChar
@ProcessCharAfterLT:
seges lodsb { Read the character that follows '<'. }
cmp AL, '@' { Check to see if it is '@', '+' or '-'. }
jz @ProcessControlCode
cmp AL, '+'
jz @ProcessControlCode
cmp AL, '-'
jz @ProcessControlCode
jmp @Continue
@PerhapsControlCode:
loop @ProcessCharAfterLT
mov AL, AH
call @CallReadBlock
jmp @ProcessCharAfterLT
@ProcessControlCodeChar:
seges lodsb { A control code sequence has begun. }
cmp AL, '>' { Process characters until a '>' is }
jz @Continue { found. }
@ProcessControlCode:
loop @ProcessControlCodeChar
mov AL, AH
call @CallReadBlock
jmp @ProcessControlCodeChar
@CallReadBlock:
pushf
push AX
push DX
push DI
end; { asm }
ReadBlock;
asm
pop DI
pop DX
pop AX
popf
mov BX, offset Table
les SI, [ Block ]
mov CX, [ Actual ]
jcxz @EndOfFile
retn
@EndOfFile:
add SP, 2
cmp AL, 0
jnz @Fini
add DI, 1
adc DX, 0
@Fini:
mov [ word ptr TempCount ], DI
mov [ word ptr TempCount + 2 ], DX
end; { asm }
FiniCount;
WordCount := TempCount;
end;
{begin}
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -