home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1994 September / Simtel-MSDOS-Sep1994-CD2.iso / disc2 / turbopas / toadadd.pas < prev    next >
Pascal/Delphi Source File  |  1986-06-06  |  9KB  |  245 lines

  1. ----TOADADD.DOC----
  2. TOADADD.PAS
  3.  
  4. Turbo Pascal Inline routines for MS-DOS systems.
  5. First release permits you to add numeric strings to numeric strings,
  6. or integers to numeric strings.
  7.  
  8. Sounds simple, but this gives you a handle on manipulating literally
  9. infinitely large numbers.  (When the number depicts more than the
  10. number of objects in the universe, that's a pretty good definition
  11. of infinite, ne?)
  12.  
  13. Code could be rewritten to permit use with Z80 systems, but I'll leave
  14. that as an exercise to the student.  (Don't you just HATE that?)
  15.  
  16. More to follow ... subtraction, multiplication, division, etc.
  17. (Keep your eyes peeled for TOADMATH.PAS.)  (Unless some other Netlandian
  18. beats me to it.)
  19.  
  20. Assembler ideas obtained from Chapter 11, "Assembler for the IBM PC and
  21. PC-XT", by Peter Abel ((C) 1984 Reston Publishing Company, Inc.)
  22. for the usual ripoff price.
  23.  
  24. Works just fine on an 80286 PC clone running PC-DOS 3.1 and Turbo 3.0
  25. .. should be fine on any MS-DOS system and any Turbo version.
  26.  
  27. Released to the public domain.  (Yep, it's my code.)
  28.  
  29. David Kirschbaum
  30. Toad Hall
  31. ABN.ISCAMS@USC-ISID.ARPA
  32.  
  33. ----TOADADD.PAS----
  34. program TOADADD.PAS;
  35.  
  36. {David Kirschbaum
  37.  Toad Hall
  38.  ABN.ISCAMS@USC-ISID.ARPA
  39.  7573 Jennings Lane
  40.  Fayetteville NC  28303
  41.  (919) 868-3471
  42.  
  43.  Released to the public domain.  For MS-DOS systems and Turbo Pascal.
  44. }
  45. {Methods to provide integer addition for huge numbers ..
  46.  
  47. Presently limited by Turbo Pascal's limitation of string
  48. variables to 255 bytes.
  49.  
  50. You COULD use an array for this, extending the length of
  51. your number string to available memory!
  52.  
  53.  String must be in Data Segment, and should be of the
  54.  format '0000001' or '003270' or whatever.
  55.  
  56.  YES, it MUST be zero-filled, and NO commas or decimals!
  57.  (We're talking multi-character integers here, remember.)
  58.  
  59. }
  60.  
  61. TYPE
  62.   Str20 = STRING[20];
  63. var
  64.   NrStr,
  65.   IntStr : Str20;
  66.   i,code : INTEGER;
  67.  
  68.  
  69. PROCEDURE Addit;
  70.   {adds two integer strings together.}
  71.   BEGIN
  72.     Inline(
  73.    $1E              {     push DS}
  74.   /$07              {     pop  ES           ;ES=DS}
  75.   /$31/$DB          {     xor  BX,BX        ;clear msbs}
  76.   /$89/$D9          {     mov  CX,BX}
  77.   /$8A/$0E/>NrStr   {     mov  CL,[>NrStr]  ;the shorter number}
  78.   /$E3/$2B          {     jcxz Exit         ;no length, forget it}
  79.  
  80.   /$8A/$1E/>IntStr  {     mov  BL,[>IntStr]   ;string length}
  81.   /$8D/$B7/>IntStr  {     lea  SI,>IntStr[BX] ;first char}
  82.   /$89/$F7          {     mov  DI,SI        ;source=destination}
  83.  
  84.   /$88/$CB          {     mov  BL,CL        ;NrStr length again}
  85.   /$8D/$9F/>NrStr   {     lea  BX,>NrStr[BX] ;point to last char}
  86.   /$51              {     push CX           ;save IntStr length}
  87.   /$56              {     push SI           ;and offsets}
  88.   /$F8              {     clc}
  89.   /$FD              {     std               ;direction right to left}
  90.   /$B4/$00          {B20: mov  AH,0         ;clear AH}
  91.   /$AC              {     lodsb             ;load IntStr byte}
  92.   /$12/$07          {     adc  AL,[BX]      ;add NrStr val}
  93.   /$37              {     aaa               ;adjust for Ascii}
  94.   /$AA              {     stosb             ;store sum in IntStr}
  95.   /$4B              {     dec  BX           ;back up NrStr}
  96.   /$E2/$F6          {     loop B20}
  97.   /$88/$25          {     mov  [DI],AH      ;at end, store carry}
  98.   /$5E              {     pop  SI           ;back to the end again}
  99.   /$89/$F7          {     mov  DI,SI        ;source=destination}
  100.   /$59              {     pop  CX           ;get back NrStr length}
  101.   /$41              {     inc  CX           ;anticipate the carry}
  102.   /$AC              {B30: lodsb             ;snarf the new val}
  103.   /$0C/$30          {     or  AL,$30        ;ascify it}
  104.   /$AA              {     stosb}
  105.   /$E2/$FA          {     loop B30}
  106.                     {exit:}
  107. );
  108.   END;
  109.  
  110. {Another method:
  111. Lets you add an integer to ANY global string variable.
  112.  
  113. Both the integer to be added, and the address of the
  114. string variable are brought in as parameters.
  115. }
  116.  
  117. PROCEDURE Add(nr : INTEGER; VAR S : Str20);
  118.   {could also be:
  119.    PROCEDURE Add(nr : INTEGER; VAR S);
  120.    using Turbo's untyped parameter capability.
  121.  
  122.    use a string variable S brought in as a parameter,
  123.    and the integer nr, also brought in as a parameter.
  124.   }
  125.   BEGIN
  126.     Inline(
  127.    $8B/$86/>NR      {   mov     AX,>nr[BP]  ;nr of spins}
  128.   /$09/$C0          {   or      AX,AX     ;anything there?}
  129.   /$74/$27          {   je      X1        ; nope, quit this mess}
  130.   /$8B/$9E/>S       {   mov     BX,>S[BP] ;snarf the string address.}
  131.                     {                     ;(LDS or LES would also work,}
  132.                     {                     ;but we're assuming S is a global}
  133.                     {                     ;variable .. makes it much simpler.)}
  134.   /$89/$DF          {   mov     DI,BX     ;offset to S}
  135.   /$43              {   inc     BX        ;bump past length byte}
  136.   /$31/$C9          {   xor     CX,CX     ;clear msb}
  137.   /$8A/$0D          {   mov     CL,[DI]   ;get our integer string length}
  138.   /$01/$CF          {   add     DI,CX     ;point to the last char in the string}
  139. {;}
  140.   /$BE/$0A/$00      {   mov     SI,10     ; put divisor in SI}
  141.   /$31/$D2          {L1:xor     DX,DX     ; clear dividend high word}
  142.   /$80/$2D/$30      {   sub     byte ptr [DI],'0'  ;deasciize the char}
  143.   /$02/$05          {   add     AL,[DI]   ;add our integer msb to the char val}
  144.   /$F7/$F6          {   div     SI        ; AX = (DX:AX)/SI, DX = remainder}
  145.   /$80/$C2/$30      {   add     DL,'0'    ; convert DL remainder byte to ascii}
  146.   /$88/$15          {   mov     byte ptr [DI],DL ; put back in string as char}
  147.   /$4F              {   dec     DI        ; back step in string}
  148.   /$39/$DF          {   cmp     DI,BX     ;hit start?}
  149.   /$76/$04          {   jbe     X1        ; yep, done}
  150.   /$09/$C0          {   or      AX,AX     ; all done? (AX = 0?)}
  151.   /$75/$E9          {   jne     L1        ; if not, do another digit}
  152. );                  {X1:}
  153.   END;  {of Add}
  154.  
  155. {A third method, assuming you'll only have ONE global
  156.  string variable you'll ALWAYS use for this adding.
  157.  (In this demo, that's IntStr.)
  158.  Saves a little time by not having to pass another parm.
  159. }
  160.  
  161. PROCEDURE Add_Int(nr : INTEGER);
  162.   { use a global string variable (in this case, IntStr),
  163.    and the integer nr, brought in as a parameter.
  164.   }
  165.   BEGIN
  166.     Inline(
  167.    $8B/$86/>NR      {   mov     AX,>nr[BP]  ;nr of spins}
  168.   /$09/$C0          {   or      AX,AX     ;anything there?}
  169.   /$74/$26          {   je      X2        ; nope, quit this mess}
  170.   /$BB/>IntStr      {   mov     BX,>IntStr ;snarf the string address.}
  171.                     {;or could be}
  172.                     {;  lea     BX,>IntStr}
  173.                     {;(LDS or LES would also work, but we're assuming}
  174.                     {; IntStr is a global variable .. makes it much}
  175.                     {; simpler, and we don't chance messing up DS.)}
  176.   /$89/$DF          {   mov     DI,BX     ;offset to IntStr}
  177.   /$43              {   inc     BX        ;bump past length byte}
  178.   /$31/$C9          {   xor     CX,CX     ;clear msb}
  179.   /$8A/$0D          {   mov     CL,[DI]   ;get our integer string length}
  180.   /$01/$CF          {   add     DI,CX     ;point to the last char in the string}
  181. {;}
  182.   /$BE/$0A/$00      {   mov     SI,10     ; put divisor in SI}
  183.   /$31/$D2          {L2:xor     DX,DX     ; clear dividend high word}
  184.   /$80/$2D/$30      {   sub     byte ptr [DI],'0'  ;deasciize the char}
  185.   /$02/$05          {   add     AL,[DI]   ;add our integer msb to the char val}
  186.   /$F7/$F6          {   div     SI        ; AX = (DX:AX)/SI, DX = remainder}
  187.   /$80/$C2/$30      {   add     DL,'0'    ; convert DL remainder byte to ascii}
  188.   /$88/$15          {   mov     byte ptr [DI],DL ; put back in string as char}
  189.   /$4F              {   dec     DI        ; back step in string}
  190.   /$39/$DF          {   cmp     DI,BX     ;hit start?}
  191.   /$76/$04          {   jbe     X2        ; yep, done}
  192.   /$09/$C0          {   or      AX,AX     ; all done? (AX = 0?)}
  193.   /$75/$E9          {   jne     L2        ; if not, do another digit}
  194. );                  {X2:}
  195.   END;  {of Add_Int}
  196.  
  197.  
  198. PROCEDURE Continue;
  199.   VAR ch : CHAR;
  200.   BEGIN
  201.     Write('Press any key to continue: ');
  202.     Repeat until keypressed; read(kbd,ch);
  203.     Writeln;
  204.   END;
  205.  
  206. begin
  207.   NrStr := '004';
  208.   IntStr := '00000000000000000000';
  209.   Writeln('First add one number string [',NrStr,']');
  210.   Writeln('to a second number string [',IntStr,']');
  211.   Write(IntStr, ' + ', NrStr, ' = ');
  212.   Addit;
  213.   Writeln(IntStr);
  214.   Continue;
  215.  
  216.   Writeln('Now, add an integer to a number string:');
  217.   FOR i := 1 TO 10 DO BEGIN
  218.     Write(IntStr, ' + ', i:2, ' = ');
  219.     Add(i,IntStr);
  220.     Writeln(IntStr);
  221.   END;
  222.   Continue;
  223.  
  224.   Writeln('Same process, but using the number string as a global:');
  225.   FOR i := 1 TO 10 DO BEGIN
  226.     Write(IntStr, ' + ', i:2, ' = ');
  227.     Add_Int(i);
  228.     Writeln(IntStr);
  229.   END;
  230.   Continue;
  231.  
  232.   Writeln('Flashy, user-friendly interactive demo.');
  233.   Writeln('Enter a positive number string (up to 19 chars).');
  234.   Writeln('(Enter a null line (CR) to quit): ');
  235.   Repeat
  236.     Readln(NrStr);
  237.     IF length(NrStr) > 19 THEN NrStr[0] := #19;  {truncate}
  238.     IF NrStr <> '' THEN BEGIN
  239.       Write(IntStr, ' + ', NrStr, ' = ');
  240.       Addit;
  241.       Writeln(IntStr);
  242.     END;
  243.   Until NrStr = '';
  244. end.
  245.