home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / PARSTP20 / PARSER.PAS < prev    next >
Pascal/Delphi Source File  |  1993-10-25  |  24KB  |  683 lines

  1. (******************************************************************************
  2. *                                   parser                                    *
  3. * Ron Loewy, 1992. A mathematical recursive decent parser +-/*^ and functions *
  4. * Version 2.0, Oct. 1993.                                                     *
  5. ******************************************************************************)
  6. unit parser;
  7. {$ifdef ovl}
  8.    {$O+,F+}
  9. {$endif}
  10. interface
  11.  
  12. uses
  13.    parseDB
  14.    ;
  15.  
  16. type  
  17.    TokenType   = (Delimiter,Non,variable,Digit,endExpr,Error,Func);
  18.    TokenPtr    = ^TokenRec;
  19.    TokenRec    = Record
  20.                      Next : TokenPtr;
  21.                      Start,Close : Byte;
  22.                   end;
  23.  
  24. var 
  25.     parserErrStr : string; 
  26.     ErrAt        : Byte;
  27.  
  28. function GetExpr(const s : string; var valid : Boolean) : Real;
  29.  
  30. implementation 
  31.  
  32. var
  33.    macro        : string;
  34.    Old_Exit  : pointer;
  35.    c  : char;
  36.    i, m  : byte;
  37.    ppText : string; { holds var of function .. }
  38. type
  39.    charSet = set of char;
  40. const
  41.    seperators  : charSet = [' ', #9, '\', ';', '*', '/', '^',
  42.                             '+', '=', '-', '%', ')'];
  43.  
  44. (******************************************************************************
  45. *                                 skipBlanks                                  *
  46. * skip blanks defined in the seperators variables, and update o               *
  47. ******************************************************************************)
  48. procedure skipBlanks(var s : string; var o : byte);
  49. var
  50.    ls : byte;
  51. const
  52.    seperators : charSet = [' ', #9];
  53. begin
  54.    ls := length(S);
  55.    while((s[o] in seperators) and
  56.          (o <= ls)) do
  57.             inc(o);
  58. end; {skipBlanks}
  59.  
  60. (******************************************************************************
  61. *                                  makeUpper                                  *
  62. * receive a string, and convert it to upper-case                              *
  63. ******************************************************************************)
  64. function makeUpper(s : string) : string;
  65. var
  66.    i : byte;
  67. begin
  68.    for i := 1 to length(s) do
  69.       if (s[i] in ['a' .. 'z']) then
  70.          s[i] := upCase(s[i]);
  71.    makeUpper := s;
  72. end; {makeUpper}
  73.  
  74. (******************************************************************************
  75. *                                  readWord                                   *
  76. * Return the next word found from the current string, and updates the offset  *
  77. * variable. if mu is true, return the upper case word.                        *
  78. ******************************************************************************)
  79. function readWord(var s : string;  var o : byte; mu : boolean; 
  80.                   const seperators : charSet) : string;
  81. var
  82.    v : string;
  83.    ls : byte;
  84. begin
  85.    skipBlanks(s, o);
  86.    v := '';
  87.    ls := length(s);
  88.    while ((not (s[o] in seperators)) and 
  89.           (o <= ls)) do begin
  90.             v := v + s[o];
  91.             inc(o);
  92.    end;
  93.    if (mu) then
  94.       v := makeUpper(v);
  95.    if ((v[length(v)] = #255) and (v <> #255)) then begin
  96.       v := copy(v, 1, length(v) - 1);
  97.       dec(o);
  98.    end;
  99.    readWord := v;
  100. end; {readWord}
  101.  
  102. (******************************************************************************
  103. *                                    DoErr                                    *
  104. ******************************************************************************)
  105. procedure DoErr(var n : TokenType);
  106. begin
  107.    n := Error;
  108.    ErrAt := i; {globl err pos}
  109. end; {doErr}
  110.  
  111. (******************************************************************************
  112. *                                 doReadWord                                  *
  113. ******************************************************************************)
  114. function doReadWord : string;
  115. var 
  116.    WordIn : string;
  117. begin
  118.      WordIn := '';
  119.      While (not(Macro [i] in
  120.                       [' ','\',';','*','/','^','+','=','-','%','(',')']))
  121.             and (i <= Length(Macro)) do
  122.      begin
  123.           WordIn := WordIn + UpCase(Macro[i]);
  124.           Inc(i);
  125.      end;
  126.      doReadWord := WordIn;
  127. end; {doreadWord}
  128.  
  129. (******************************************************************************
  130. *                                 ReadNumber                                  *
  131. ******************************************************************************)
  132. function ReadNumber : Real;
  133. var 
  134.    Number : Real;
  135.    Code   : Integer;
  136.    StrNum : string;
  137. begin
  138.      StrNum := doReadWord;
  139.      if StrNum[1] = '.' then StrNum := '0' + StrNum;
  140.      Val(StrNum,Number,Code);
  141.      if Code <> 0 then Number := 0;
  142.      ReadNumber := Number;
  143. end; {readNumber}
  144.  
  145. procedure Level1(var Result : Real; var n : TokenType) ; forward;
  146.  
  147. (******************************************************************************
  148. *                                getFuncOrVar                                 *
  149. ******************************************************************************)
  150. procedure getFuncOrVar(var n : tokenType);
  151. begin
  152.    m := i;
  153.    ppText := readWord(macro, m, true, seperators);
  154.    if ((pos('(', ppText) <> 0) or (ppText = 'PI') or (ppText = 'E')) then
  155.       n := func
  156.    else
  157.       n := variable;
  158. end; {getFuncOrVar}
  159.  
  160. (******************************************************************************
  161. *                                  GetToken                                   *
  162. ******************************************************************************)
  163. function GetToken : TokenType;
  164. var 
  165.    Temp : string;
  166.    n    : TokenType;
  167. begin
  168.      SkipBlanks(macro, i);
  169.      if (Macro[i] in ['+','-','/','*','=','^','%','(',')']) then
  170.                         n := Delimiter
  171.                     else if (Macro[i] in ['0'..'9','.']) then
  172.                         n := Digit
  173.                     else if (Macro[i] = ';') then
  174.                         n := endExpr
  175.                     else if (Macro[i] in ['a'..'z','A'..'Z'])
  176.                         then getFuncOrVar(n)
  177.                     else 
  178.                         n := Non;
  179.      GetToken := n;
  180. end; {getToken}
  181.  
  182. (******************************************************************************
  183. *                                  MatchFunc                                  *
  184. ******************************************************************************)
  185. function MatchFunc(Match : string; var Result : Real; var n : TokenType) :
  186.                                                                Boolean;
  187. var 
  188.    j : Byte;
  189. begin
  190.      j := i; {restore i if no match}
  191.      if (doReadWord = Match) then begin
  192.         MatchFunc := True;
  193.         skipblanks(macro, i);
  194.         if (Macro [i] <> '(') then DoErr(n)
  195.            else begin
  196.                      Inc(i);
  197.                      n := GetToken;
  198.                      Level1(Result,n);
  199.                      SkipBlanks(macro, i); {Reach closing parenthasis}
  200.                      if Macro[i] <> ')' then DoErr(n);
  201.                      Inc(i);
  202.                      SkipBlanks(macro, i);
  203.            end;
  204.      end else begin
  205.          MatchFunc := False;
  206.          i := j; {no Func Match, restore}
  207.      end;
  208. end; {matchFunc}
  209.  
  210. (******************************************************************************
  211. *                                 MatchToken                                  *
  212. ******************************************************************************)
  213. function MatchToken(Match : string) : boolean;
  214. var 
  215.    j : byte;
  216. begin
  217.     j := i;
  218.     if (doreadWord = match) then MatchToken := True
  219.         else begin
  220.             MatchToken := False;
  221.             i := j;
  222.         end; {else}
  223. end; {matchToken}
  224.  
  225. (******************************************************************************
  226. *                                    doPI                                     *
  227. ******************************************************************************)
  228. function doPI(var r:real) : boolean;
  229. begin
  230.     doPI := matchToken('PI');
  231.     r := pi;
  232. end; {doPI}
  233.  
  234. (******************************************************************************
  235. *                                     doE                                     *
  236. ******************************************************************************)
  237. function doE(var r:real) : boolean;
  238. begin
  239.     doE := matchToken('E');
  240.     r := exp(1.0);
  241. end; {doE}
  242.  
  243. (******************************************************************************
  244. *                                    DoSin                                    *
  245. ******************************************************************************)
  246. function DoSin(var Result : Real; var n : TokenType) : Boolean;
  247. var 
  248.    r : Boolean;
  249. begin
  250.      r := MatchFunc('SIN',Result,n);
  251.      Result := sin(Result);
  252.      DoSin := r;
  253. end; {doSin}
  254.  
  255. (******************************************************************************
  256. *                                    DoExp                                    *
  257. ******************************************************************************)
  258. function DoExp(var Result : Real; var n : TokenType) : Boolean;
  259. var 
  260.    r : Boolean;
  261. begin
  262.      r := MatchFunc('EXP',Result,n);
  263.      Result := exp(Result);
  264.      DoExp := r;
  265. end; {doSin}
  266.  
  267. (******************************************************************************
  268. *                                    DoCos                                    *
  269. ******************************************************************************)
  270. function DoCos(var Result : Real; var n : TokenType) : Boolean;
  271. var 
  272.    r : Boolean;
  273. begin
  274.      r := MatchFunc('COS',Result,n);
  275.      Result := cos(Result);
  276.      DoCos := r;
  277. end; {doCos}
  278.  
  279. (******************************************************************************
  280. *                                    DoLn                                     *
  281. ******************************************************************************)
  282. function DoLn(var Result : Real; var n : TokenType) : Boolean;
  283. var 
  284.    r : Boolean;
  285. begin
  286.      r := MatchFunc('LN',Result,n);
  287.      if (Result > 0.0) then Result := ln(Result)
  288.         else DoErr(n);
  289.      DoLn := r;                   
  290. end; {doLn}
  291.  
  292. (******************************************************************************
  293. *                                   DoLog10                                   *
  294. ******************************************************************************)
  295. function DoLog10(var Result : Real; var n : TokenType) : Boolean;
  296. var 
  297.    r : Boolean;
  298. begin
  299.      r := MatchFunc('LOG10',Result,n);
  300.      if (Result > 0.0) then Result := ln(Result)/ln(10.0)
  301.         else DoErr(n);
  302.      DoLog10 := r;                   
  303. end; {doLog10}
  304.  
  305. (******************************************************************************
  306. *                                   DoLog2                                    *
  307. ******************************************************************************)
  308. function DoLog2(var Result : Real; var n : TokenType) : Boolean;
  309. var 
  310.    r : Boolean;
  311. begin
  312.      r := MatchFunc('LOG2',Result,n);
  313.      if (Result > 0.0) then Result := ln(Result)/ln(2.0)
  314.         else DoErr(n);
  315.      DoLog2 := r;                   
  316. end; {doLog2}
  317.  
  318. (******************************************************************************
  319. *                                    DoAbs                                    *
  320. ******************************************************************************)
  321. function DoAbs(var Result : Real; var n : TokenType) : Boolean;
  322. var 
  323.    r : Boolean;
  324. begin
  325.      r := MatchFunc('ABS',Result,n);
  326.      Result := Abs(Result);
  327.      DoAbs := r;
  328. end; {doAbs}
  329.  
  330. (******************************************************************************
  331. *                                  DoArcTan                                   *
  332. ******************************************************************************)
  333. function DoArcTan(var Result : Real; var n : TokenType) : Boolean;
  334. var 
  335.    r : Boolean;
  336. begin
  337.      r := MatchFunc('ARCTAN',Result,n);
  338.      Result := ArcTan(Result);
  339.      DoArcTan := r;
  340. end; {doArcTan}
  341.  
  342. (******************************************************************************
  343. *                                    DoSqr                                    *
  344. ******************************************************************************)
  345. function DoSqr(var Result : Real; var n : TokenType) : Boolean;
  346. var 
  347.    r : Boolean;
  348. begin
  349.      r := MatchFunc('SQR',Result,n);
  350.      Result := Sqr(Result);
  351.      DoSqr := r;
  352. end; {doSqr}
  353.  
  354. (******************************************************************************
  355. *                                   DoSqrt                                    *
  356. ******************************************************************************)
  357. function DoSqrt(var Result : Real; var n : TokenType) : Boolean;
  358. var 
  359.    r : Boolean;
  360. begin
  361.      r := MatchFunc('SQRT',Result,n);
  362.      Result := Sqrt(Result);
  363.      DoSqrt := r;
  364. end; {doSqrt}
  365.  
  366. (******************************************************************************
  367. *                                    DoTan                                    *
  368. ******************************************************************************)
  369. function DoTan(var Result : Real; var n : TokenType) : Boolean;
  370. var 
  371.    r : Boolean;
  372. begin
  373.      r := MatchFunc('TAN',Result,n);
  374.      if ( cos(result) <> 0 ) then 
  375.     Result := Sin(Result) / cos(Result)
  376.      else doErr(n);
  377.      DoTan := r;
  378. end; {doTan}
  379.  
  380. (******************************************************************************
  381. *                                   DoCoTan                                   *
  382. ******************************************************************************)
  383. function DoCoTan(var Result : Real; var n : TokenType) : Boolean;
  384. var 
  385.    r : Boolean;
  386. begin
  387.      r := MatchFunc('COTAN',Result,n);
  388.      if ( sin(result) <> 0 ) then 
  389.     Result := cos(Result) / sin(Result)
  390.      else doErr(n);
  391.      DoCoTan := r;
  392. end; {doCoTan}
  393.  
  394. (******************************************************************************
  395. *                                  DoArcSin                                   *
  396. ******************************************************************************)
  397. function DoArcSin(var Result : Real; var n : TokenType) : Boolean;
  398. var 
  399.    r : Boolean;
  400. begin
  401.      r := MatchFunc('ARCSIN',Result,n);
  402.      if (abs(Result) < 1.0) then
  403.     Result := arcTan(Result/sqrt(1-result*result))
  404.      else doErr(n);
  405.      DoArcSin := r;
  406. end; {doArcSin}
  407.  
  408. (******************************************************************************
  409. *                                  DoArcCos                                   *
  410. ******************************************************************************)
  411. function DoArcCos(var Result : Real; var n : TokenType) : Boolean;
  412. var 
  413.    r : Boolean;
  414. begin
  415.      r := MatchFunc('ARCCOS',Result,n);
  416.      if ((Result <> 0.0) and (result < 1.0)) then
  417.        Result := arcTan(sqrt(1-result*result)/result)
  418.     else doErr(n);
  419.     DoArcCos := r;
  420. end; {doArcCos}
  421.  
  422. (******************************************************************************
  423. *                                   DoFunc                                    *
  424. ******************************************************************************)
  425. procedure DoFunc(var Result : Real; var n : TokenType);
  426. begin
  427.      case Macro [i] of
  428.           's','S' : begin
  429.                          if not(DoSin(Result,n)) then
  430.                             if not(DoSqr(Result,n)) then
  431.                                if not(DoSqrt(Result,n)) then
  432.                             DoErr(n);
  433.                     end;
  434.           'c','C' : begin
  435.                          if not(DoCos(Result,n)) then
  436.                if not(DoCoTan(result,n)) then
  437.                             DoErr(n);
  438.                     end;
  439.           'l','L' : begin
  440.                          if not(DoLn(Result,n)) then
  441.                 if not(doLog10(result,n)) then
  442.                     if not(doLog2(result,n)) then
  443.                             DoErr(n);
  444.                     end;
  445.           'a','A' : begin
  446.                          if not(DoAbs(Result,n)) then
  447.                             if not(DoArcTan(Result,n)) then
  448.                 if not(doArcSin(Result,n)) then
  449.                      if not(doArcCos(result,n))
  450.                                then DoErr(n);
  451.                     end;
  452.           'e','E' : begin
  453.                          if not(DoExp(Result,n)) then
  454.                 if not(doE(result)) then
  455.                                      DoErr(n);
  456.                     end;
  457.       't','T' : begin
  458.             if not(doTan(result,n)) then
  459.                 doErr(n);
  460.             end;
  461.       'p','P' : begin
  462.             if not(doPI(result)) then 
  463.                 doErr(n);
  464.             end;     
  465.           else DoErr(n);
  466.      end; {case}
  467. end;
  468.  
  469. (******************************************************************************
  470. *                                  Primitive                                  *
  471. ******************************************************************************)
  472. procedure Primitive(var Result : Real; var n : TokenType);
  473. begin
  474.    if (n = variable) then begin
  475.       i := m;
  476.       if (symbolTbl^.bringByKey(ppText)) then
  477.          result := symbolTbl^.current^.value
  478.       else begin
  479.          result := 0.0;
  480.          symbolTbl^.current^.value := 0.0;
  481.          symbolTbl^.writeByKey(ppText);
  482.       end;
  483.    end else if (n = Digit) then 
  484.    Result := ReadNumber
  485.    else if (n = Func) then 
  486.    DoFunc(Result,n);
  487.    SkipBlanks(macro, i);
  488. end;
  489.  
  490. (******************************************************************************
  491. *                                   Level6                                    *
  492. * handle parenthasis                                                          *
  493. ******************************************************************************)
  494. procedure Level6(var Result : Real; var n : TokenType);
  495. begin
  496.    if ((n = Delimiter) and (Macro [i] = '(')) then begin
  497.       Inc(i);
  498.       n := GetToken;
  499.       Level1(Result,n);
  500.       SkipBlanks(macro, i); {Reach closing parenthasis}
  501.       if (Macro[i] <> ')') then 
  502.          DoErr(n);
  503.       Inc(i);
  504.       SkipBlanks(macro, i);
  505.    end else 
  506.       Primitive(Result,n);
  507. end; { level6}
  508.  
  509. (******************************************************************************
  510. *                                   Level5                                    *
  511. ******************************************************************************)
  512. procedure Level5(var Result : Real; var n : TokenType);
  513. var 
  514.    op : Char;
  515. begin
  516.    op := Macro [i];
  517.    if (op in ['-','+']) then 
  518.       Inc(i);
  519.    n := GetToken;
  520.    Level6(Result,n);
  521.    if (op = '-') then 
  522.       Result := - (Result);
  523. end; { level5 }
  524.  
  525. (******************************************************************************
  526. *                                    Sign                                     *
  527. * returns -1 if num < 0, 1 otherwise                                          *
  528. ******************************************************************************)
  529. function Sign(Number : Real) : Real;
  530. begin
  531.      if (Number < 0.0) then Sign := -1.0
  532.         else Sign := 1.0;
  533. end; { sign }
  534.  
  535. (******************************************************************************
  536. *                                   Level4                                    *
  537. ******************************************************************************)
  538. procedure Level4(var Result : Real; var n : TokenType);
  539. var 
  540.    Hold : Real;
  541. begin
  542.    Level5(Result,n);
  543.    if (n <> Error) then
  544.       if (macro[i] = '^') then begin
  545.          Inc(i);
  546.          n := GetToken;
  547.          Level4(Hold,n);
  548.          if (Result = 0.0) then
  549.             if (hold = 0.0) then 
  550.                result := 1.0
  551.             else 
  552.                result := 0.0
  553.          else 
  554.             Result := Sign(Result) * Exp(Hold * Ln(Abs(Result)));
  555.          SkipBlanks(macro, i);
  556.       end;  { case of ^ }
  557. end; {level4}
  558.  
  559. (******************************************************************************
  560. *                                   Level3                                    *
  561. * handle multiply/divide                                                      *
  562. ******************************************************************************)
  563. procedure Level3(var Result : Real; var n : TokenType);
  564. var 
  565.    Hold : Real;
  566.    op   : Char;
  567. begin
  568.    Level4(Result,n);
  569.    if (n <> Error) then begin
  570.       SkipBlanks(macro, i);
  571.       While Macro [i] in ['*','/','%'] do begin
  572.          op := Macro[i];
  573.          Inc(i);
  574.          n := GetToken;
  575.          Level4(Hold,n);
  576.          if op = '*' then Result := Result * Hold
  577.             else begin
  578.           if (hold = 0.0) then doErr(n)
  579.           else 
  580.         if op = '/' then Result := Result / Hold
  581.                        else Result := Trunc(Result) mod Trunc(Hold);
  582.        end;
  583.          SkipBlanks(macro, i);
  584.       end;
  585.    end; {not error}
  586. end; { level 3 }
  587.  
  588. (******************************************************************************
  589. *                                   Level2                                    *
  590. * handle add/sub                                                              *
  591. ******************************************************************************)
  592. procedure Level2(var Result : Real; var n : TokenType);
  593. var 
  594.     Hold : Real;
  595.     op   : Char;
  596. begin
  597.    Level3(Result,n);
  598.    if (n <> Error) then begin
  599.       SkipBlanks(macro, i);
  600.       While (Macro [i] in ['+','-']) do begin
  601.          op := Macro [i];
  602.          inc(i);
  603.          n := GetToken;
  604.          Level3(Hold,n);
  605.          if op = '+' then Result := Result + Hold
  606.             else Result := Result - Hold;
  607.          SkipBlanks(macro, i);
  608.       end; {while}
  609.    end; {not error}
  610. end; { level2 }
  611.  
  612. (******************************************************************************
  613. *                                   Level1                                    *
  614. * handle assign                                                               *
  615. ******************************************************************************)
  616. procedure Level1(var Result : Real; var n : TokenType);
  617. var 
  618.     Slot : Char;
  619.     mt   : TokenType;
  620.     j    : Byte;
  621.     mv   : string;
  622. begin
  623.    if (n = variable) then begin
  624.       j := i; {save  i}
  625.       i := m;
  626.       mv := ppText;
  627.       mt := GetToken;
  628.       if ((mt = Delimiter) and (Macro [i] = '=') and (i <=length(Macro)))
  629.       then begin
  630.             Inc(i);
  631.             n := GetToken;
  632.             Level2(Result,n);
  633.             symbolTbl^.current^.value := Result;
  634.             symbolTbl^.writeByKey(mv);
  635.       end else begin
  636.          i := j; {restore ..}
  637.          level2(Result,n);
  638.       end; {not a variable = ...}
  639.    end {variable case} else
  640.       Level2(Result,n);
  641. end; { level 1 }
  642.  
  643. (******************************************************************************
  644. *                                   GetExpr                                   *
  645. ******************************************************************************)
  646. function GetExpr;
  647. var 
  648.    Result : Real;
  649.    n      : TokenType;
  650. begin
  651.    macro := s;
  652.    i := 1;
  653.    Result := 0; {if no result returned}
  654.    n := GetToken;
  655.    if (Not (n in [endExpr,Non])) then 
  656.       Level1(Result,n);
  657.    if ((n <> endExpr) and (i < Length(Macro))) then 
  658.       Dec(i);
  659.    GetExpr := Result;
  660.    if (n = Error) then 
  661.       Valid := False
  662.    else 
  663.       Valid := True;
  664. end; {getExpr}
  665.  
  666. (******************************************************************************
  667. *                                 error_exit                                  *
  668. * whenever we exit, we do it from here, and clean the memory ..               *
  669. ******************************************************************************)
  670. procedure error_exit; far;
  671. begin
  672.    dispose(symbolTbl, done);
  673. end; {error_exit}
  674.  
  675. (******************************************************************************
  676. *                                    MAIN                                     *
  677. ******************************************************************************)
  678. begin
  679.    new(symbolTbl, create('ST'));
  680.    Old_Exit := exitproc;
  681.    exitproc := @Error_Exit;
  682. end.
  683.