home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / sonderh1 / aosupn.pas < prev    next >
Pascal/Delphi Source File  |  1986-11-25  |  12KB  |  373 lines

  1. {---------------------------------------------------------------------------}
  2. { Dieses Programm wandelt unter Verwendung der Datentypen 'stack' und 'queue'
  3.   einen mathematichen Ausdruck aus dem Algebraischen-Ordungs-System (AOS) in
  4.   die Umgekehrt-Polnische-Notation um.                                      }
  5.  
  6. PROGRAM aos_to_upn;
  7.  
  8. CONST cr = #13;                             { Tastencode fuer ENTER/RETURN  }
  9.  
  10. TYPE stpointer = ^stelem;                   { Zeiger auf einen Stackeintrag }
  11.      qupointer = ^quelem;                   { Zeiger auf einen Queueeintrag }
  12.      stack = stpointer;                     { Anker des Stacks (oberstes)   }
  13.      queue = RECORD
  14.                head,                        { Anker der Queue: Anfang       }
  15.                tail: qupointer              {                  und Ende     }
  16.              END;
  17.      information = char;
  18.      stelem = RECORD
  19.                 info: information;          { Stackelement besteht aus      }
  20.                 last: stpointer             { Information und Vorgaenger.   }
  21.               END;
  22.      quelem = RECORD
  23.                 info: information;          { Queue-Element besteht aus     }
  24.                 next: qupointer;            { Information und Nachfolger.   }
  25.               END;
  26.  
  27. VAR aos_schlange, upn_schlange: queue;      { zum speichern der Ausdruecke  }
  28.  
  29. {============================================================================}
  30.  
  31. { Die Routinen dieses Abschnittes definieren die Operationen auf den neuen
  32.   Datentyp Schlange. Sie koennen zusammen mit den Typdeklarationen in der
  33.   TYPE-Daklaration auch allgemein verwendet werden, da von der Art der In-
  34.   formation kein Gebrauch gemacht wird. }
  35.  
  36. {---------------------------------------------------------------------------}
  37.  
  38. PROCEDURE create_queue (VAR anker: queue);
  39.  
  40. { Die einfachste Operation ist das Erzeugen einer Schlange. Sie muss immer
  41.   aufgerufen werden, bevor eine Schlange erstmals verwendet wird. Nach
  42.   dem Aufruf ist die Schlange leer - zum Loeschen empfielt sich diese Proze-
  43.   dur aber nicht, da eventuell Elemente, die in ihr gespeichert sind, danach
  44.   brach liegen.                                                             }
  45.  
  46. BEGIN
  47.   anker.head := nil;
  48.   anker.tail := nil
  49. END;
  50.  
  51. {----------------------------------------------------------------------------}
  52.  
  53. PROCEDURE clear_queue (VAR anker: queue);
  54.  
  55. { Diese Prozedur loescht nun eine Schlange, wobei die Speicherplaetze ihrer
  56.   Elemente wiederverwendet werden, also nicht ungenutzt bleiben. }
  57.  
  58. VAR kopf: qupointer;
  59.  
  60. BEGIN
  61.   WHILE anker.head <> nil DO
  62.   BEGIN
  63.     kopf := anker.head;
  64.     anker.head := anker.head^.next;
  65.     dispose(kopf)              { ggf. hier explicit_dispose aus der 1. Folge }
  66.   END;
  67. END;
  68.  
  69. {----------------------------------------------------------------------------}
  70.  
  71. PROCEDURE enter (VAR anker: queue; info: information);
  72.  
  73. { Fuer die Information 'info' wird eine dynamische Variable erzeugt, die an
  74.   die Schlange angehaengt wird.                                              }
  75.  
  76. VAR schwanz: qupointer;
  77.  
  78. BEGIN
  79.   new(schwanz);
  80.   schwanz^.info := info;
  81.   schwanz^.next := nil;
  82.   IF anker.head = nil THEN
  83.     anker.head := schwanz
  84.   ELSE
  85.     anker.tail^.next := schwanz;
  86.   anker.tail := schwanz;
  87. END;
  88.  
  89. {----------------------------------------------------------------------------}
  90.  
  91. PROCEDURE remove (VAR anker: queue; VAR info: information; VAR err: boolean);
  92.  
  93. { Der Kopf der Schlange, also ihr vorderstes und zuerst eingelesenes Element,
  94.   wird abgetrennt und die darin stehende Information in 'info' zurueckgegeben.
  95.   Sollte die Schlange leer sein, wird das Fehlerflag 'err' gesetzt.          }
  96.  
  97. VAR kopf: qupointer;
  98.  
  99. BEGIN
  100.   IF anker.head=nil THEN
  101.     err := true
  102.   ELSE
  103.   BEGIN
  104.     err := false;
  105.     kopf := anker.head;
  106.     info := kopf^.info;
  107.     anker.head := anker.head^.next;
  108.     dispose(kopf);                       { ggf. esplicit_dispose aus Folge 1 }
  109.   END;
  110. END;
  111.  
  112. {----------------------------------------------------------------------------}
  113.  
  114. PROCEDURE head (VAR anker: queue; VAR info: information; VAR err: boolean);
  115.  
  116. { Aehnlich der obigen Prozedur wird auch hier die Information des Kopfelem.
  117.   in 'info' zurueckgegeben und ggf. das Errorflag gesetzt, doch bleibt der
  118.   Eintrag am Kopf der Schlange erhalten.                                     }
  119.  
  120. BEGIN
  121.   IF anker.head=nil THEN
  122.     err := true
  123.   ELSE
  124.   BEGIN
  125.     err := false;
  126.     info := anker.head^.info;
  127.   END;
  128. END;
  129.  
  130. {----------------------------------------------------------------------------}
  131.  
  132. FUNCTION empty_queue (anker: queue): boolean;
  133.  
  134. { Diese Funktion gibt zurueck, ob die Schlange leer ist (true) oder mindes-
  135.   tens ein Element enthaelt (false).                                         }
  136.  
  137. BEGIN
  138.   empty_queue := anker.tail=nil;
  139. END;
  140.  
  141. {============================================================================}
  142.  
  143. { Dieses Modul definiert zusammen mit den TYPE-Deklarationen den Datentyp
  144.   'stack' und seine Operationen. }
  145.  
  146. {----------------------------------------------------------------------------}
  147.  
  148. PROCEDURE create_stack (VAR anker: stack);
  149.  
  150. { Vor der ersten Benutzung eines stack muss dieser erzeugt werden. Bezueglich
  151.   des Loeschens siehe 'create_queue'.                                        }
  152.  
  153. BEGIN
  154.   anker := nil;
  155. END;
  156.  
  157. {----------------------------------------------------------------------------}
  158.  
  159. PROCEDURE clear_stack (VAR anker: stack);
  160.  
  161. { Diese Prozedur loescht nun einen Stack und gibt die von ihm belegten
  162.   Speicherplaetze zur Wiederverwendung frei.                                 }
  163.  
  164. VAR top: stpointer;
  165.  
  166. BEGIN
  167.   WHILE anker <> nil DO
  168.   BEGIN
  169.     top := anker^.last;
  170.     dispose(anker);                      { ggf. explicit_dispose aus Folge 1 }
  171.     anker := top;
  172.   END;
  173. END;
  174.  
  175. {----------------------------------------------------------------------------}
  176.  
  177. PROCEDURE push (VAR anker: stack; info: information);
  178.  
  179. { Fuer die uebergebene Information wird eine dynamische Variable erzeugt und
  180.   diese auf den Stapel gelegt.                                               }
  181.  
  182. VAR top: stpointer;
  183.  
  184. BEGIN
  185.   top := anker;
  186.   new(anker);
  187.   anker^.info := info;
  188.   anker^.last := top;
  189. END;
  190.  
  191. {----------------------------------------------------------------------------}
  192.  
  193. PROCEDURE pop (VAR anker: stack; VAR info: information; VAR err: boolean);
  194.  
  195. { Als Gegenstueck zu 'push' wird hier das oberste Element vom Stapel genommen
  196.   und seine Information zurueckgegeben. Ist der Stapel leer, wird das
  197.   Errorflag gesetzt.                                                         }
  198.  
  199. VAR top: stack;
  200.  
  201. BEGIN
  202.   IF anker = nil THEN
  203.     err := TRUE
  204.   ELSE
  205.   BEGIN
  206.     err := false;
  207.     info := anker^.info;
  208.     top := anker^.last;
  209.     dispose(anker);
  210.     anker := top;
  211.   END;
  212. END;
  213.  
  214. {----------------------------------------------------------------------------}
  215.  
  216. FUNCTION empty_stack (anker: stack): BOOLEAN;
  217.  
  218. { Ist der Stack leer, dann wird true, sonst true zurueckgegeben.             }
  219.  
  220. BEGIN
  221.   empty_stack := anker=nil;
  222. END;
  223.  
  224. {----------------------------------------------------------------------------}
  225.  
  226. PROCEDURE tos (anker: stack; VAR info: information; VAR err: boolean);
  227.  
  228. { Ohne das oberste Element vom Stapel zu entfernen, wird seine Information
  229.   zurueckgegeben und ggf. das Errorflag gesetzt.                             }
  230.  
  231. BEGIN
  232.   IF anker=nil THEN
  233.     err := true
  234.   ELSE
  235.   BEGIN
  236.     err := false;
  237.     info := anker^.info;
  238.   END;
  239. END;
  240.  
  241. {============================================================================}
  242.  
  243. { Dieses Modul stellt Ein- und Ausgaberoutinen fuer genau die Schlangen zur
  244.   Verfuegung, die in diesem Programm gebraucht werden, naemlich mit Elementen
  245.   vom Typ 'char'. }
  246.  
  247. {----------------------------------------------------------------------------}
  248.  
  249. PROCEDURE lese (VAR schlange: queue);
  250.  
  251. { Es wird eine Folge der moeglichen Zeichen eingelesen und diese in eine
  252.   Schlange geschrieben, bei Fehlerhafter Eingabe wird das betreffende Zeichen
  253.   ignoriert, es gibt keine Fehlermeldung. Die Eingabe wird durch '=' beendet.
  254.   Die Dateiangabe 'trm' ermoeglicht in Turbo-Pacal die zeichenweise Eingabe
  255.   mit Bildschirmecho.                                                        }
  256.  
  257. VAR info: information;
  258.  
  259. BEGIN
  260.   create_queue(schlange);
  261.   REPEAT
  262.     Read(trm, info);
  263.     IF info IN ['a'..'z', '+', '-', '*', '/', '^', '=', '(', ')'] THEN
  264.     enter(schlange, info)
  265.   UNTIL info = '=';
  266.   WriteLn;
  267. END;
  268.  
  269. {----------------------------------------------------------------------------}
  270.  
  271. PROCEDURE schreibe (schlange: queue);
  272.  
  273. { Die uebergebene Schlange wird auf den Bildschirm ausgegeben.               }
  274.  
  275. VAR info: information;
  276.     err: BOOLEAN;
  277.  
  278. BEGIN
  279.   remove(schlange, info, err);
  280.   WHILE NOT(err) DO
  281.   BEGIN
  282.     write(info);
  283.     remove(schlange, info, err);
  284.   END;
  285.   WriteLn;
  286. END;
  287.  
  288. {============================================================================}
  289.  
  290. { Die folgenden Routinen bearbeiten die Anwendung: 'Umwandlung AOS-UPN',
  291.   dabei werden die oben definierten Datentypen 'stack' und 'queue' mit ihren
  292.   Operationen verwendet. }
  293.  
  294. {----------------------------------------------------------------------------}
  295.  
  296. FUNCTION prio (op: CHAR): INTEGER;
  297.  
  298. { Diese Funktion gibt die Prioritaet einer mathematischen Operation zurueck.
  299.   Je hoeher der zurueckgegebene Wert, desto vorrangiger wird die Operation
  300.   ausgefuehrt.                                                               }
  301.  
  302. BEGIN
  303.   CASE op OF
  304.     '('    : prio := 0;
  305.     '+','-': prio := 1;
  306.     '*','/': prio := 2;
  307.     '^'    : prio := 3;
  308.   END;
  309. END;
  310.  
  311. {----------------------------------------------------------------------------}
  312.  
  313. PROCEDURE aos_to_upn (aos: queue; VAR upn: queue);
  314.  
  315. { Hier findet die eingentliche Umwandlung der AOS-Darstellung in UPN statt.
  316.   Der Algorithmus ist im Begleittext naeher erklaert. Es findet keine Kon-
  317.   trolle auf Korrektheit des AOS-Ausdrucks statt!                            }
  318.  
  319. VAR top: information;
  320.     stapel: stack;
  321.     err: BOOLEAN;
  322.     info: information;
  323.  
  324. BEGIN
  325.   create_stack(stapel);
  326.   create_queue(upn);
  327.   remove(aos, info, err);
  328.   push(stapel, '(');
  329.   WHILE NOT(err) DO
  330.   BEGIN
  331.     CASE info OF
  332.       'a'..'z'           : enter(upn,info);
  333.       '+','-','*','/','^': BEGIN
  334.                              tos(stapel, top, err);
  335.                              WHILE prio(info) < prio(top) DO
  336.                              BEGIN
  337.                                pop(stapel, top, err);
  338.                                enter(upn, top);
  339.                                tos(stapel, top, err);
  340.                               END;
  341.                               push(stapel, info);
  342.                             END;
  343.       '('                : push(stapel, info);
  344.       ')','='            : BEGIN
  345.                              pop(stapel, top, err);
  346.                              WHILE top <> '(' DO
  347.                              BEGIN
  348.                                enter(upn, top);
  349.                                pop(stapel, top, err);
  350.                              END;
  351.                            END;
  352.     END;
  353.     remove(aos, info, err);
  354.   END;
  355. END;
  356.  
  357. {============================================================================}
  358.  
  359. BEGIN
  360.   WriteLn;
  361.   WriteLn('*** Programm zur Umwandlung von AOS in UPN');
  362.   WriteLn;
  363.   WriteLn('Es koennen nur Ausdruecke bestehend aus Buchstaben (a..z),');
  364.   WriteLn('den Operationen +, -, *, / und ^ sowie Klammern ( ) verwendet');
  365.   WriteLn('werden, fehlerhafte Zeichen werden ignoriert.');
  366.   WriteLn;
  367.   Write('AOS: ');
  368.   lese(aos_schlange);
  369.   aos_to_upn(aos_schlange, upn_schlange);
  370.   write('UPN: ');
  371.   schreibe(upn_schlange);
  372. END.
  373.