% Content-encoding: UTF-8 \documentclass[ngerman]{article} \usepackage[T1]{fontenc} \usepackage[latin1]{inputenc} \setcounter{secnumdepth}{0} \setcounter{tocdepth}{0} \begin{document} \title{Geburtstage} \author{André Elgeti} \maketitle \section{Zusammenfassung} Dies soll einmal darstellen, wie eine Lösung in Forth aussehen kann. Ich habe bewusst das Volksforth genutzt, weil es leicht in andere Systeme umgeschrieben werden kann und gewissermaßen eine Basis bildet. Der Artikel ist an den Newcomer--Anfänger gerichtet, und ist deshalb etwas ausführlicher ausgefallen. Ich habe versucht die Gedanken aus dem Buch \emph{Thinking Forth} einfließen zu lassen. Ich hoffe, es ist mir gelungen. Bewusst habe ich auf jeden Vergleich zu anderen Programmiersprachen verzichtet. \begin{multicols}{2} \section{Aufgabe} Jeder von uns stand sicher schon einmal vor der Situation, einen Geburtstag vergessen zu haben. Dieses Programm soll nun dabei helfen, dass das nie wieder passieren wird. \section{1.~Interface} Das Wort \verb|Geburtstage| soll anzeigen:\\ \begin{verbatim} Onkel Willi noch 100 Tage, Tante Laura noch 132 Tage \end{verbatim} $\vdots$ \section{2.~Daten} Da die Anzahl unserer Freunde relativ konstant ist, können wir ihre Daten in einen Screen einlesen. Die Daten werden durch den Spitznamen aufgerufen. z.~B.\ \begin{verbatim} variable willi ," 12.5.1954" ," Onkel Willi" ," Wilhelm Lange" ," Am Brotsteig 5" ," 18200 Bratstett" \end{verbatim} Aus den Daten eine verkettete Liste zu erzeugen, ist ziemlich einfach. Der Aufruf einer Variablen übergibt deren Adresse auf den Stack. Aufgrund der Segmentierung hat sie ebenfalls eine Länge von 16Bit und kann somit auch in einer Variable abgelegt werden. Wenn beispielsweise \verb|norbert| auf \verb|willi| folgt, kann man eingeben. \begin{verbatim} norbert willi ! \end{verbatim} Der Aufruf von \begin{verbatim} willi @ \end{verbatim} legt dann die Adresse des nächsten Datensatzes auf den Stack. Die Worte \verb|Geburtstag| und \verb|Anschrift| müssen an die im Wörterbuch gespeicherten Daten zugreifen können. Dazu gibt es das Wort Daten: \begin{verbatim} : daten ( anz addr – addr länge) 2 + swap begin dup 0> while 1 - swap dup c@ + 1 + swap repeat drop ; \end{verbatim} \section{3.~Worte} \subsection{3.1.~Kernfunktion} Die Kernfunktion soll aus zwei Daten, dem aktuellen Datum und dem Geburtsdatum, die Differenz erzeugen. Nun haben wir die Herausforderung, dass diese Funktion in einigen Programmiersprachen hinzugeladen werden kann. Die Anlage der Aufgabe zeigt, dass sich das Ergebnis zwischen –365 und 365 bewegen kann, je nach Werten. Die Aufgabe vereinfacht sich also dahin, die Tagesnummer im Jahr festzustellen. Vereinfacht könnte man sagen: $\mathrm{Tagesnummer} =\\ \hspace*{\fill}31 * \mathrm{Monatsnummer} (1 ... 12) + \mathrm{Tageszahl} (1 ... 31) - 31$ Was einen Wertebereich von 1 für den 1.~1.\ bis 372 für den 31.~12.\ ergäbe. Das ist nun nicht günstig, deshalb wird das anders gelöst. Es wird ein Feld angelegt, dessen Inhalte die Nummern der 1.~ der Monate zeigen. \begin{verbatim} Create monate 1, 32 , 60, 91 , 121 , 152 , 182 , 213 , 243 , 274 , 304 , 335 , \end{verbatim} \verb|Create| legt den Eintrag \verb|Monate| auf dem Wörterbuch an, und mit den Kommas werden dahinter die Zahlen für die Monatsanfänge gespeichert. Das Wort \verb|Tagesnummer| ( tag monat ) würde dann so funktionieren: \begin{enumerate} \item hole von create die Nummer des Monatsersten \begin{verbatim} monate + @ \end{verbatim} \item Füge die Tage hinzu und ziehe 1 ab \begin{verbatim} + 1 – \end{verbatim} \end{enumerate} Das Wort heißt also \begin{verbatim} : Tagesnummer ( tag monat -- tagesnummer) monate + @ + 1 - ; \end{verbatim} Nun benötigen wir noch ein Wort, womit wir aus dem Geburtsdatum die beiden Zahlen herausschneiden können und als solche auf den Stack legen können. In Forth werden die Zeichenketten abgespeichert: \begin{verbatim} 08 33 31 2E 30 35 2E 36 37 \end{verbatim} was dem Geburtsdatum \verb|31.05.67| entspricht. Die \verb|08| ist das \emph{Counter-Byte} und gibt die Länge der Zeichenkette an. Beim Aufruf der Variablen wird die Adresse des \emph{Counter-Bytes} übergeben. Das Ziel ist es jetzt, die Zeichenkette \verb|33 31| auszuschneiden und in \verb|1F| für $31$ umzuwandeln. Für den zweiten Teil werden die Zahlen als Zeichen auf den Stack gelegt und eine Funktion erzeugt daraus eine Zahl: Beim Zehner die oberen vier Bit abschneiden: \verb|15 and| \\ Die Zahl verzehnfachen: \verb|10 *| \\ Den Einer hervorholen: \verb |swap| \\ Beim Einer die oberen vier Bit abschneiden: \verb|15 and| \\ Zusammenaddieren: \verb|+| \begin{verbatim} : Zahlbilden( char1 char10 --- zahl) 15 and 10 * swap 15 and + ; \end{verbatim} Dieses Wort kann nach dem Horner-Schema erweitert werden, genügt hier aber so vollauf. \begin{verbatim} : Tagesdatum ( addresse --- Tagesnummer) dup 1+ c@ swap dup 2 + c@ rot zahlbilden swap dup 4 + c@ swap 5 + c@ zahlbilden tagesnummer ; \end{verbatim} Das Systemdatum wird mit \verb|date@ (--- d m y)| auf dem Stack abgelegt \begin{verbatim} : Tagesdifferenz(adresse --- Differenz) Tagesdatum Date@ drop ( Jahreszahl löschen) Tagesnummer - (Differenz bilden) ; \end{verbatim} \begin{center} \begin{tabular}{|l|l|l|l|} \hline & TOS & 2nd & 3rd \\ \hline Adr & & & \\ \hline Dup & Adr & Adr & \\ \hline 1 + c@ & Char1 & Adr & \\ \hline Swap & Adr & Char1 & \\ \hline Dup & Adr & Adr & Char1\\ \hline 2 + c@ & Char2 & Adr & Char1\\ \hline Rot & Char1 & Char2 & Adr\\ \hline Zahlb. & Zahl1 & Adr &\\ \hline Swap & Adr & Zahl1 &\\ \hline Dup & Adr & Adr & Zahl1\\ \hline 4 + c@ & Char3 & Adr & Zahl1\\ \hline Swap & Adr & Char3 & Zahl1\\ \hline 5 + c@ & Char4 & Char3 & Zahl1 \\ \hline swap & Char3 & Char4 & Zahl1\\ \hline Zahlb & Zahl2 & Zahl1 &\\ \hline \end{tabular} Tabelle 1: Stackdiagramm zu \texttt{Tagesdatum} \end{center} Nun fassen wir dies in einer Funktion zusammen, die uns angibt, wie lange es noch Zeit ist bis zum Geburtstag der betreffenden Person: \begin{verbatim} : Geburtstag ( Addresse --- ) dup 2 swap daten count type space ." noch" 1 daten tagesdifferenz space . ." Tage" cr ; \end{verbatim} Die Eingabe \begin{verbatim} Willi Geburtstag \end{verbatim} ergibt dann \begin{verbatim} Onkel Willi noch 126 Tage. \end{verbatim} Daraus ergibt sich dann \begin{verbatim} : Geburtstage willi ( 1. Eintrag) begin ( Schleifenbeginn) dup ( Adresse doppeln) geburtstag ( Ausgabe ) @ dup =0 ( ist die nächste Adresse NULL ?) until ( wenn nicht, neue Schleife) ; \end{verbatim} \section{Zusammenfassung:} Das System zeigt nun die Zeitdifferenzen zu den Geburtstagen an, allerdings nur in einer Richtung. Als Nächstes könnte die Anzeige der Adressen und das Schreiben der Glückwunschkarten erfolgen. \end{multicols} \section{Links:} \emph{Thinking Forth}, Leo Brodie, \url{http://thinking-forth.sourceforge.net/} \newpage \section{Listing} \label{geburtstagelisting} \listinginput[1]{1}{2007-02/Geburtstage.fs} % \end{document}