home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / dtx9202 / aripars / parsarit.pas < prev   
Pascal/Delphi Source File  |  1991-01-29  |  6KB  |  331 lines

  1.  
  2. (* LISTING 1:  A program to parse and evaluate ordinary integer arithmetic expressions *)
  3.  
  4. (* This is a Texas Instruments-style calculator. It parses arithmetic expressions using*)
  5. (* the usual precedence rules.*)
  6. (* Written by Jonathan Amsterdam, December 1984; BYTE August 1985, S. 141-145*)
  7.  
  8.  
  9. program TICalc;
  10.  
  11.     const
  12.         endOfFile = 0;  (* special character signifying end of file *)
  13.         empty = 127;  (* character used to indicate that savedChar is empty *)
  14.         endOfLine = 13;  (* special character signifying end of line *)
  15.  
  16.     type
  17.         nodetype = (binop, unop, number);
  18.         node = ^noderec;
  19.         noderec = record
  20.                 case tag : nodetype of
  21.                     binop: (
  22.                             operator: CHAR;
  23.                             leftOperand, rightOperand: node
  24.                     );
  25.                     unop: (
  26.                             uOperator: CHAR;
  27.                             operand: node
  28.                     );
  29.                     number: (
  30.                             num: INTEGER
  31.                     );
  32.             end;
  33.  
  34.     var
  35.         savedChar: CHAR;
  36.         digits: set of CHAR;
  37.  
  38.  
  39. (* input functions *)
  40.  
  41.     function getChar: CHAR;
  42. (*  Useful low-level character input. Returns special characters at end of file and end of line*)
  43.         var
  44.             c: CHAR;
  45.     begin
  46.         if savedCHAR <> chr(empty) then
  47.             begin
  48.                 getCHAR := savedChar;
  49.                 savedChar := chr(empty);
  50.             end
  51.         else if eof then
  52.             getChar := chr(endOfFile)
  53.         else if eoln then
  54.             begin
  55.                 getChar := chr(endOfLine);
  56.                 readln;
  57.             end
  58.         else
  59.             begin
  60.                 read(c);
  61.                 getChar := c;
  62.             end;
  63.     end;
  64.  
  65.  
  66.     procedure ungetChar (c: CHAR);
  67. (* Allows one character at a time to be pushed back on the input. *)
  68.     begin
  69.         if savedChar = chr(empty) then
  70.             savedChar := c
  71.         else
  72.             writeln('½½ungetChar½½ can½½t unget more than one character at a time ');
  73.     end;
  74.  
  75.  
  76.     function nextChar: CHAR;
  77. (* Skips over blanks. *)
  78.         var
  79.             c: CHAR;
  80.     begin
  81.         repeat
  82.             c := getChar
  83.         until c <> ' ';
  84.         nextChar := c;
  85.     end;
  86.  
  87.  
  88.     function charToInt (c: CHAR): INTEGER;
  89. (* Converts a numeric character to an integer. *)
  90.     begin
  91.         if not (c in digits) then
  92.             begin
  93.                 writeln('charToInt : ', c, 'is not a digit');
  94.                 charToInt := 0;
  95.             end
  96.         else
  97.             charToint := ord(c) - ord('0');
  98.     end;
  99.  
  100.  
  101.     function getNum (c: CHAR): INTEGER;
  102. (* Reads a number from the input. The first digit of the number has already been read *)
  103. (*and is passed as an argument. *)
  104.         var
  105.             n: INTEGER;
  106.     begin
  107.         n := 0;
  108.         repeat
  109.             n := 10 * n + charToInt(c);
  110.             c := getChar;
  111.         until not (c in digits);
  112.         ungetChar(c);
  113.         getNum := n;
  114.     end;
  115.  
  116.  
  117. (*  node creation functions *)
  118. (* The following three functions create nodes for the parse tree. The first*)
  119. (*  two each return NIL if their node arguments are NIL. *)
  120.  
  121.     function binopNode (opor: CHAR; lopand, ropand: node): node;
  122.         var
  123.             n: node;
  124.     begin
  125.         if (lopand = nil) or (ropand = nil) then
  126.             binopNode := nil
  127.         else
  128.             begin
  129.                 New(n, binop);
  130.                 with n^ do
  131.                     begin
  132.                         tag := binop;
  133.                         operator := opor;
  134.                         leftOperand := lopand;
  135.                         rightOperand := ropand;
  136.                     end;
  137.                 binopNode := n;
  138.             end;
  139.     end;
  140.  
  141.  
  142.     function unopNode (opor: CHAR; opand: node): node;
  143.         var
  144.             n: node;
  145.     begin
  146.         if opand = nil then
  147.             unopNode := nil
  148.         else
  149.             begin
  150.                 new(n, unop);
  151.                 with n^ do
  152.                     begin
  153.                         tag := unop;
  154.                         uOperator := opor;
  155.                         operand := opand;
  156.                     end;
  157.                 unopNode := n;
  158.             end;
  159.     end;
  160.  
  161.  
  162.     function numberNode (i: INTEGER): node;
  163.         var
  164.             n: node;
  165.     begin
  166.         new(n, number);
  167.         with n^ do
  168.             begin
  169.                 tag := number;
  170.                 num := i;
  171.             end;
  172.         numberNode := n;
  173.     end;
  174.  
  175.  
  176. (* tree-printing procedures *)
  177.  
  178.     procedure ptree (n: node; depth: integer);
  179.     begin
  180.         with n^ do
  181.             case tag of
  182.                 binop: 
  183.                     begin
  184.                         ptree(leftOperand, depth + 2);
  185.                         writeln(' ' : depth, operator);
  186.                         ptree(rightOperand, depth + 2);
  187.                     end;
  188.                 unop: 
  189.                     begin
  190.                         writeln(' ' : depth, uoperator);
  191.                         ptree(operand, depth + 2);
  192.                     end;
  193.                 number: 
  194.                     writeln(' ' : depth, num);
  195.             end;
  196.     end;
  197.  
  198.  
  199.     procedure PrintTree (n: node);
  200.     begin
  201.         ptree(n, 0);
  202.     end;
  203.  
  204.  
  205. (* parser *)
  206. (* Each of the three parsing functions returns NIL if an error occurs in the parse. *)
  207.  
  208.     function term: node;
  209.     FORWARD;
  210.  
  211.     function factor: node;
  212.     FORWARD;
  213.  
  214.     function expr: node;
  215. (*  An expression is either a term, or a term +,- an expression. *)
  216.         var
  217.             c: CHAR;
  218.             n: node;
  219.     begin
  220.         n := term;
  221.         expr := n;
  222.         if n <> nil then
  223.             begin
  224.                 c := nextChar;
  225.                 if (c = '+') or (c = '-') then
  226.                     expr := binopNode(c, n, expr)
  227.                 else if c <> chr(endOfLine) then
  228.                     ungetChar(c);
  229.             end;
  230.     end;
  231.  
  232.  
  233.     function term;(*:node*)
  234. (*  A term is either a factor, or a factor *,/ a term. *)
  235.         var
  236.             c: CHAR;
  237.             n: node;
  238.     begin
  239.         n := factor;
  240.         term := n;
  241.         if n <> nil then
  242.             begin
  243.                 c := nextChar;
  244.                 if (c = '*') or (c = '/') then
  245.                     term := binopNode(c, n, term)
  246.                 else
  247.                     ungetChar(c);
  248.             end;
  249.     end;
  250.  
  251.  
  252.     function factor;(*:node*)
  253. (* A factor is either a number, or a - followed by a factor, or a parenthesized expression. *)
  254.         var
  255.             c: CHAR;
  256.     begin
  257.         c := nextChar;
  258.         if c in digits then
  259.             factor := numberNode(getNum(c))
  260.         else if c = '-' then
  261.             factor := unopNode(c, factor)
  262.         else if c = '(' then
  263.             begin
  264.                 factor := expr;
  265.                 if nextChar <> ')' then
  266.                     writeln('close parenthesis expected');
  267.             end
  268.         else
  269.             begin
  270.                 writeln('illegal expression');
  271.                 factor := nil;
  272.             end;
  273.     end;
  274.  
  275.     function eval (n: node): REAL;
  276. (* Evaluates a parse tree. Assumes that the only binary operations are +, -, *,*)
  277. (* and / and that the only unary operation is -. *)
  278.         var
  279.             op1, op2: REAL;
  280.     begin
  281.         with n^ do
  282.             case tag of
  283.                 binop: 
  284.                     begin
  285.                         op1 := eval(leftOperand);
  286.                         op2 := eval(rightOperand);
  287.                         case operator of
  288.                             '+': 
  289.                                 eval := op1 + op2;
  290.                             '-': 
  291.                                 eval := op1 - op2;
  292.                             '*': 
  293.                                 eval := op1 * op2;
  294.                             '/': 
  295.                                 eval := op1 / op2;
  296.                         end;
  297.                     end;
  298.                 unop: 
  299.                     eval := -eval(operand);
  300.                 number: 
  301.                     eval := num;
  302.             end;
  303.     end;
  304.  
  305.  
  306.     procedure run;
  307.         var
  308.             n: node;
  309.             c: CHAR;
  310.     begin
  311.         repeat
  312.             write('> ');
  313.             n := expr;
  314.             if n <> nil then
  315.                 begin
  316.                     writeln;
  317.                     printTree(n);
  318.                     writeln;
  319.                     writeln(eval(n) : 0 : 2);
  320.                 end;
  321.         until FALSE;
  322.     end;
  323.  
  324.  
  325. begin (*** MAIN PROGRAM ***)
  326.     writeln('TI - style calculator');
  327.     writeln('Enter an arithmetic expression and hit < RETURN >');
  328.     writeln('I will print a parse tree and evaluate the expression .');
  329.     digits := ['0'..'9'];
  330.     run;
  331. end.