home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / dtx9202 / aripars / arithmet.pas < prev    next >
Pascal/Delphi Source File  |  1992-01-06  |  8KB  |  295 lines

  1. (* ------------------------------------------------------ *)
  2. (*                      ARITHMET.PAS                      *)
  3. (*          (c) 1991 Burkhard Wittek & DMV-Verlag         *)
  4. (* ------------------------------------------------------ *)
  5. PROGRAM ArithmetikParser;
  6.  
  7. CONST
  8.   Zahlen     = ['0'..'9'];
  9.   ZeilenEnde = 13;
  10.   DateiEnde  = 0;
  11.   leer       = 127;
  12.  
  13. TYPE
  14.   KnotenTyp      = (binaerOp, unaerOp, Zahl);
  15.   Knoten         = ^KnotenStruktur;
  16.   KnotenStruktur = RECORD
  17.     CASE Schritt : KnotenTyp OF
  18.       binaerOp : (binaererOperator        : CHAR;
  19.                   linkerSohn, rechterSohn : Knoten);
  20.       unaerOp  : (unaererOperator         : CHAR;
  21.                   operand                 : Knoten);
  22.       Zahl     : (num                     : INTEGER);
  23.   END;
  24.  
  25. VAR
  26.   gesichertesZeichen : CHAR;
  27.  
  28. (* ------------------------------------------------------ *)
  29. (* Eingabe-Prozeduren/Funktionen                          *)
  30.  
  31.   FUNCTION LeseZeichen : CHAR;
  32.     (* Zeichen-Eingabe (bis Zeilen-/File-Ende) *)
  33.   VAR
  34.     c : CHAR;
  35.   BEGIN
  36.     IF gesichertesZeichen <> Chr(leer) THEN BEGIN
  37.       LeseZeichen := gesichertesZeichen;
  38.       gesichertesZeichen := Chr(leer);
  39.     END ELSE IF EoLn THEN BEGIN
  40.       LeseZeichen := Chr(ZeilenEnde);  ReadLn;
  41.     END ELSE IF EoF THEN
  42.       LeseZeichen := Chr(DateiEnde)
  43.     ELSE BEGIN
  44.       Read(c); LeseZeichen := c;
  45.     END;
  46.   END;
  47.  
  48.   PROCEDURE AufhebenLeseZeichen(c : CHAR);
  49.     (* ein Zeichen zurück auf den Eingabebuffer *)
  50.   BEGIN
  51.     IF gesichertesZeichen = Chr(leer) THEN
  52.       gesichertesZeichen := c
  53.     ELSE
  54.       WriteLn('Immer nur ein Zeichen kann gepusht werden!');
  55.   END;
  56.  
  57.   FUNCTION naechstesZeichen : CHAR;
  58.     (* Löschen von Blanks *)
  59.   VAR
  60.     c : CHAR;
  61.   BEGIN
  62.     REPEAT
  63.       c := LeseZeichen
  64.     UNTIL c <> ' ';
  65.     naechstesZeichen := c;
  66.   END;
  67.  
  68.   FUNCTION ZeichenzuZahl(c : CHAR) : INTEGER;
  69.     (* Umwandlung char -> integer *)
  70.   BEGIN
  71.     IF NOT (c IN Zahlen) THEN BEGIN
  72.       WriteLn(c, 'ist kein ZahlZeichen!');
  73.       ZeichenzuZahl := 0;
  74.     END ELSE
  75.       ZeichenzuZahl := Ord(c) - Ord('0');
  76.   END;
  77.  
  78.   FUNCTION EingabeZahl(c : CHAR) : INTEGER;
  79.     (* Lesen eines Eingabezeichens *)
  80.   VAR
  81.     Pos : INTEGER;
  82.   BEGIN
  83.     Pos := 0;
  84.     REPEAT
  85.       Pos := 10 * Pos + ZeichenzuZahl(c);
  86.       c := LeseZeichen;
  87.     UNTIL NOT (c IN Zahlen);
  88.     AufhebenLeseZeichen(c);
  89.     EingabeZahl := Pos;
  90.   END;
  91.  
  92. (* ------------------------------------------------------ *)
  93. (* Prozeduren/Funktionen zur Knoten-Generierung des       *)
  94. (* Parsing-Baumes                                         *)
  95.  
  96.   FUNCTION binaerOpKnoten(OPor      : CHAR;
  97.                           linksund,
  98.                           rechtsund : Knoten) : Knoten;
  99.     (* binäre Knoten *)
  100.   VAR
  101.     Pos : Knoten;
  102.   BEGIN
  103.     IF (linksund = NIL) OR (rechtsund = NIL) THEN
  104.       binaerOpKnoten := NIL
  105.     ELSE BEGIN
  106.       Pos^.Schritt := binaerOp;
  107.       New(Pos);
  108.       WITH Pos^ DO BEGIN
  109.         Schritt          := binaerOp;
  110.         binaererOperator := OPor;
  111.         linkerSohn       := linksund;
  112.         rechterSohn      := rechtsund;
  113.       END;
  114.       binaerOpKnoten := Pos;
  115.     END;
  116.   END;
  117.  
  118.   FUNCTION unaerOpKnoten(OPor  : CHAR;
  119.                          OPand : Knoten) : Knoten;
  120.     (* unäre Knoten *)
  121.   VAR
  122.     Pos : Knoten;
  123.   BEGIN
  124.     IF OPand = NIL THEN
  125.       unaerOpKnoten := NIL
  126.     ELSE BEGIN
  127.       Pos^.Schritt := unaerOp;
  128.       New(Pos);
  129.       WITH Pos^ DO BEGIN
  130.         Schritt         := unaerOp;
  131.         unaererOperator := OPor;
  132.         operand         := OPand;
  133.       END;
  134.       unaerOpKnoten := Pos;
  135.     END;
  136.   END;
  137.  
  138.   FUNCTION ZahlKnoten(i : INTEGER) : Knoten;
  139.     (* terminale Zahlen-Knoten *)
  140.   VAR
  141.     Pos : Knoten;
  142.   BEGIN
  143.     Pos^.Schritt := Zahl;
  144.     New(Pos);
  145.     WITH Pos^ DO BEGIN
  146.       Schritt := Zahl;
  147.       Num     := i;
  148.     END;
  149.     ZahlKnoten := Pos;
  150.   END;
  151.  
  152. (* ------------------------------------------------------ *)
  153. (* Prozeduren/Funktionen zum arithmetischen Parser        *)
  154.  
  155.   FUNCTION Term   : Knoten;  FORWARD;
  156.   FUNCTION Faktor : Knoten;  FORWARD;
  157.  
  158.   FUNCTION Ausdruck : Knoten;
  159.     (* Ausdruck = ein Term bzw.
  160.        ein Term '+' / '-' ein Ausdruck) *)
  161.   VAR
  162.     c   : CHAR;
  163.     Pos : Knoten;
  164.   BEGIN
  165.     Pos := Term;
  166.     Ausdruck := Pos;
  167.     IF Pos <> NIL THEN BEGIN
  168.       c := naechstesZeichen;
  169.       IF (c = '+') OR (c = '-') THEN
  170.         Ausdruck := binaerOpKnoten(c, Pos, Ausdruck)
  171.       ELSE IF c <> Chr(ZeilenEnde) THEN
  172.         AufhebenLeseZeichen(c);
  173.     END;
  174.   END;
  175.  
  176.   FUNCTION Term;
  177.     (* Term = ein Faktor bzw.
  178.        ein Faktor '*' / '/' ein Term)  *)
  179.   VAR
  180.     c   : CHAR;
  181.     Pos : Knoten;
  182.   BEGIN
  183.     Pos  := Faktor;
  184.     Term := Pos;
  185.     IF Pos <> NIL THEN BEGIN
  186.       c := naechstesZeichen;
  187.       IF (c = '*') OR (c = '/') THEN
  188.         Term := binaerOpKnoten(c, Pos, Term)
  189.       ELSE AufhebenLeseZeichen(c);
  190.     END;
  191.   END;
  192.  
  193.   FUNCTION Faktor;
  194.     (* Faktor = eine Zahl bzw. ein
  195.        Minus ('-') gefolgt von einem Faktor
  196.        bzw. ein geklammerter Ausdruck  *)
  197.   VAR
  198.     c : CHAR;
  199.   BEGIN
  200.     c := naechstesZeichen;
  201.     IF c IN Zahlen THEN
  202.       Faktor := ZahlKnoten(EingabeZahl(c))
  203.     ELSE IF c = '-' THEN
  204.       Faktor := unaerOpKnoten(c, Faktor)
  205.     ELSE IF c = '(' THEN BEGIN
  206.       Faktor := Ausdruck;
  207.       IF naechstesZeichen <> ')' THEN
  208.         Writeln('Schließende Klammer wurde erwartet');
  209.     END ELSE BEGIN
  210.       WriteLn('Kein wohlgeformter Ausdruck');
  211.       Faktor := NIL;
  212.     END;
  213.   END;
  214.  
  215. (* ------------------------------------------------------ *)
  216. (* Prozeduren/Funktionen zum Zeichnen des Parsing-Baums   *)
  217.  
  218.   PROCEDURE Baum(Pos : Knoten; Tiefe : INTEGER);
  219.   BEGIN
  220.     WITH Pos^ DO
  221.       CASE Schritt OF
  222.         binaerOp : BEGIN
  223.                      Baum(linkerSohn, Tiefe+3);
  224.                      WriteLn(' ' : Tiefe, binaererOperator);
  225.                      Baum(rechterSohn, Tiefe+3);
  226.                    END;
  227.         unaerOp  : BEGIN
  228.                      WriteLn(' ' : Tiefe, unaererOperator);
  229.                      Baum(operand, Tiefe+3);
  230.                    END;
  231.         Zahl     : WriteLn(' ' : Tiefe, num);
  232.       END;
  233.   END;
  234.  
  235.   PROCEDURE ZeichneBaum(Pos : Knoten);
  236.   BEGIN
  237.     Baum(Pos, 3);
  238.   END;
  239.  
  240. (* ------------------------------------------------------ *)
  241. (* Funktion zur Berechnung des geparsten                  *)
  242. (* semantischen Baums                                     *)
  243.  
  244.   FUNCTION Evaluation(n : Knoten) : REAL;
  245.   VAR
  246.     op1, op2 : REAL;
  247.   BEGIN
  248.     WITH n^ DO
  249.       CASE Schritt OF
  250.         binaerOp : BEGIN
  251.                      op1 := Evaluation(linkerSohn);
  252.                      op2 := Evaluation(rechterSohn);
  253.                      CASE binaererOperator OF
  254.                        '+' : Evaluation := op1 + op2;
  255.                        '-' : Evaluation := op1 - op2;
  256.                        '*' : Evaluation := op1 * op2;
  257.                        '/' : Evaluation := op1 / op2;
  258.                      END;
  259.                    END;
  260.         unaerOp  : Evaluation := -Evaluation(operand);
  261.         Zahl     : Evaluation := num;
  262.       END;
  263.   END;
  264.  
  265.   PROCEDURE ProgrammLauf;
  266.     (* Hauptprozedur des Programmlaufs *)
  267.   VAR
  268.     Pos : Knoten;
  269.     c   : CHAR;
  270.   BEGIN
  271.     REPEAT
  272.       Write('> ');
  273.       Pos := Ausdruck;
  274.       IF Pos <> NIL THEN BEGIN
  275.         Writeln;
  276.         ZeichneBaum(Pos);
  277.         WriteLn;  WriteLn(Evaluation(Pos):0:2);
  278.       END;
  279.     UNTIL FALSE;
  280.   END;
  281.  
  282. BEGIN
  283.   WriteLn;
  284.   WriteLn('CIS München - Pascal-Arithmetik-Parsing- ',
  285.           'und Berechnungs-Programm');
  286.   WriteLn;
  287.   WriteLn('Eingabe ist: Ein arithmetischer Ausdruck ',
  288.           'plus < RETURN >');
  289.   WriteLn('Ausgabe ist: Ein Parsing-Baum des Ausdrucks ',
  290.           'plus Ergebnis.');
  291.   ProgrammLauf;
  292. END.
  293. (* ------------------------------------------------------ *)
  294. (*                 Ende von ARITHMET.PAS                  *)
  295.