1

我正在用汇编程序在 Turbo Pascal 中编写一个程序,以完成 QB 4.5 中的“rset”语句。"Rset" 将把字符串与变量中的最后一个字节对齐,这意味着字符串将在变量的末尾保存在变量中,而不是保存在第一个字节中。这是我制作的代码,但我没有看到任何反应:

procedure rset(var s:string);

var
s_copy:string;
index,
s_size:integer;
s_offset,
s_seg,
s_copy_offset,
s_copy_seg:word;

l:byte;

label
again;

begin

l:=length(s);

if l=0 then exit;

index:=1;
while copy(s,index,1)='' do
inc(index);

s_copy:=copy(s,index,l);

s:='';
s_size:=sizeof(s);
s_offset:=ofs(s)+s_size-1;
s_copy_offset:=ofs(s_copy)+l-1;
s_copy_seg:=seg(s_copy);
s_seg:=seg(s);

asm
mov cl, [l]
mov si, [s_copy_offset]
mov di, [s_offset]

again:
mov es, [s_copy_seg]
mov al, [byte ptr es:si]
mov es, [s_seg]
mov [byte ptr es:di], al

dec si
dec di

dec cl
jnz again
end;

end;
4

1 回答 1

0

The RSet statement in BASIC works with two strings. Your code works from a single string and can make sense if that string has some whitespace at its right end. Because then it is possible to RTrim the string and shift the remaining characters to the right inserting space characters on the left.
In below program I have implemented this approach in the RSet procedure.

If we were to faithfully replicate how BASIC's RSet statement works, then we need to use two strings, for the syntax is: RSet lvalue = rvalue, where lvalue is a string variable and rvalue can be any string expression.
In below program I have implemented this way of doing it in the qbRSet procedure.

Both RSet and qbRSet are pure assembler procedures. They don't require the usual begin and end; statements, just asm and end; are enough. And see how easy it is to refer to a variable via the lds and les assembly instructions. Do notice that assembly code should:

  • always preserve the DS segment register as well as BP, SP, and SS
  • never leave the direction flag set

The demo program is written in Turbo Pascal 6.0 and allows you to test the proposed codes with a variety of inputs. This is important so you can check out if it will work correctly in cases where strings are empty, very small, or very long.

program MyRSet;
type
  str20 = string[20];

var
  S, B : string;
  A    : str20;

procedure RSet(var S : string); assembler;
  asm
        les  di, S        (* ES:DI points at length byte of S *)
        xor  cx, cx
        mov  cl, [es:di]  (* CX is length of S *)
        cmp  cx, 1
        jbe  @@3
        add  di, cx       (* ES:DI points at last char of S *)
        mov  si, di       (* ES:SI points at last char of S *)

        { Collecting space characters starting at the end }
        mov  al, ' '
  @@1:  cmp  [es:si], al
        jne  @@2          (* Found a non-space character *)
        dec  si
        dec  cx
        jnz  @@1
        jz   @@3          (* Done, S is spaces only *)

        { Copying the RTrimmed content to the rear of the string}
  @@2:  std
        rep seges movsb

        { Left padding with spaces }
        mov  cx, di
        sub  cx, si
        rep stosb
        cld
  @@3:
  end;

procedure qbRSet(var Dst : str20; Src : string); assembler;
  asm
        push ds
        les  di, Dst      (* ES:DI points at length byte of Dst *)
        lds  si, Src      (* DS:SI points at length byte of Src *)
        xor  dx, dx
        mov  dl, [es:di]  (* DX is length of Dst *)
        xor  cx, cx
        mov  cl, [si]     (* CX is length of Src *)
        add  di, dx       (* ES:DI points at last char of Dst *)
        add  si, cx       (* DS:SI points at last char of Src *)
        sub  dx, cx
        jnb  @@1          (* Src is not longer than Dst *)
        add  cx, dx       (* else we use Copy(Src,1,Length(Dst)) *)
        add  si, dx
        xor  dx, dx       (*      and no leading whitespace *)
  @@1:  std
        rep movsb         (* Copying all or part of Src *)
        mov  al, ' '
        mov  cx, dx
        rep stosb         (* Prepending space characters *)
        cld
        pop  ds
  end;

BEGIN
  writeln('1. RSet A$ - Input text that ends with some whitespace');
  writeln('======================================================');
  repeat
    writeln('Input the A$. Use * to stop.');
    readln(S);
    if S <> '*' then
    begin
      RSet(S);
      writeln('|', S, '|')
    end;
  until S = '*';

  writeln;

  writeln('2. RSet A$=B$ - Length of A$ is 20');
  writeln('==================================');
  repeat
    fillchar(A[1],20,'?'); A[0] := #20;
    writeln('Input the B$. Use * to stop');
    readln(B);
    if B <> '*' then
    begin
      qbRSet(A, B);
      writeln('|', A, '|')
    end;
  until B = '*'
END.
于 2021-01-11T00:51:07.843 回答