%% LyX 2.0.0 created this file. For more info, see http://www.lyx.org/. %% Do not edit unless you really know what you are doing. \documentclass[ngerman]{article} \usepackage[T1]{fontenc} \usepackage[utf8x]{inputenc} \usepackage{multicol} \usepackage{babel} %\begin{document} \vspace*{2em} \title{Xchars im Microcontroller} \author{Bernd Paysan} \maketitle \begin{abstract} \emph{Matthias Trute fragte im IRC, was er denn tun müsse, um das Xchar--Wordset in seinem amForth zu implementieren. Ich nutze die freie Seite in der VD, das mal kurz zu erklären. Das Xchar--Wordset ist ein Modul des Forth200x--Standards, mit dem ASCII--kompatible Erweiterungen von Zeichensätzen, auch solche mit variablen Zeichenlängen, verarbeitet werden können. Das ist vor allem das populäre UTF--8, aber auch GBK (VR China), Big5 (Taiwan) oder JIS X 0213 (Japan) haben variable Länge und sind ASCII--kompatibel.} \end{abstract} \begin{multicols}{2} \section{Einleitung} Die Motivation zu der Xchar--Erweiterung kommt aus der Anforderung der ISO, zu Forth doch bitte auch ein Internationalization--Konzept hinzuzufügen. Xchars lösen nur einen Teil davon, nämlich die Zeichensätze --- ANS--Forth selbst war ein reines ASCII--System. Anders als etwa Python, das zwischen Strings und Byte--Arrays unterscheidet, und Strings bei der Ein/Ausgabe recodieren muss, wollte ich keine solch gravierenden Eingriffe in das Forth--System vornehmen. Xchar ist also so gebaut, dass man mit wenig Aufwand ein vorhandenes System fit für UTF--8 oder andere Encodings mit variabler Länge machen kann. So ein Standard--Text ist nicht unbedingt leicht zu lesen, weil Standards immer viel mit Politik zu tun haben, und man das dann so formuliert, dass auch verschiedene Implementierungsoptionen möglich sind. In der Praxis kommen diese Optionen selten in Frage. So definiert Xchar ein ,,pchar{};`` in den meisten Implementierungen nennt man das einfach ,,Byte{}.`` Ein Xchar (extended character) besteht halt aus einem oder mehreren Bytes. String--Befehle selbst funktionieren ohne Änderungen mit Xchars, weil Strings nach wie vor einfach Byte--Arrays sind. Natürlich muss man darauf achten, dass alles 8--Bit--clean ist, auch das Wörterbuch. Dann hat man schon ein System, das weitgehend funktioniert, wenn man ihm UTF--8--Quelltext vorlegt. Gforth 0.6.2, die letzte Version ohne Xchars, schluckt das, ohne zu murren. Nur der Zeileneditor hakt, wenn man Xchars eingibt, und mit dem Cursor darüber hinweglaufen will --- weil der eben nichts über die variable Zeichenlänge weiß. amForth, das hat Matthias gleich ausprobiert, verschluckt sich im Wörterbuch, wenn man UTF--8--Zeichen benutzt. Aber das ist sicher ein Problem, das leicht zu beheben ist. Damit ist das Forth--System dann schon mal 8--Bit--clean, das ist die halbe Miete. Was das Xchar--Wordset nicht macht: Es unterstützt nicht das Umwandeln von einem Encoding in ein anderes. Man kann also nicht mal ein UTF--8--Terminal, mal ein Latin--1--Terminal verwenden, und sich darauf verlassen, dass das dann alles geht. Wenn man solche Features haben möchte, kann man die außerhalb des Standards implementieren, wie es einem gerade gefällt. \section{Minimaler Befehlssatz} Man muss nicht viel implementieren, um das Xchar--Wordset auf einen Controller zu bringen. Die Erweiterungen (XCHAR EXT) sind nicht Pflicht, und auch nicht nötig, um einfache Operationen auszuführen. Viel mehr wird man auf dem Controller auch nicht machen, nur XCHAR-- ist interessant. Ich definiere die Wörter so, dass man sie auf einem Controller einfach implementieren kann. \begin{description} \item [{X--SIZE}] ( xc--addr u1 --- u2 ) Liefert die Länge des ersten Xchars im String --- maximal u1. Kann man sehr einfach implementieren: \begin{small} \begin{verbatim} : x-size ( xc-addr u1 -- u2 ) >r dup xc@+ drop - r> min ; \end{verbatim} \end{small} \item [{XC--SIZE}] ( xchar --- u ) Liefert die Länge des Zeichens im Speicher. Auch das sehr einfach zu implementieren: \begin{small} \begin{verbatim} Create xc-buf 4 allot : xc-size ( xchar -- u ) xc-buf xc!+ xc-buf - ; \end{verbatim} \end{small} \item [{XC@+}] ( xc--addr1 --- xc--addr2 xchar ) Liest ein Xchar aus dem String, analog zu COUNT. Für UTF--8 kann man sich an die Referenz--Implementierung halten: \begin{small} \begin{verbatim} : xc@+ ( xc-addr -- xc-addr' u ) count dup $80 u< IF EXIT THEN $7F and $40 >r BEGIN dup r@ and WHILE r@ xor 6 lshift r> 5 lshift >r >r count $3F and r> or REPEAT r> drop ; \end{verbatim} \end{small} \item [{XC!+}] ( xchar xc--addr1 --- xc--addr2 ) Speichert ein Xchar in einem String, und gibt die nächste unbenutzte Adresse zurück --- also das Gegenstück zu XC@+. Auch hier der Verweis auf die Referenz--Implementierung für UTF--8: \begin{small} \begin{verbatim} : xc!+ ( xchar xc-addr -- xc-addr' ) over $80 u< IF tuck c! char+ EXIT THEN >r 0 swap $3F BEGIN 2dup u> WHILE 2/ >r dup $3F and $80 or swap 6 rshift r> REPEAT $7F xor 2* or r> BEGIN over $80 u< 0= WHILE tuck c! char+ REPEAT nip ; \end{verbatim} \end{small} \item [{XC!+?}] ( xchar xc--addr1 u1 --- xc--addr2 u2 flag ) Diese Variante von XC!+ schützt vor Buffer--Overflows. Man kann das mit XC--SIZE leicht implementieren: \begin{small} \begin{verbatim} : xc!+? ( xchar xc-addr1 u1 -- xc-addr2 u2 flag ) >r over xc-size r@ u> IF nip r> false EXIT THEN r> over + >r xc!+ r> over - true ; \end{verbatim} \end{small} \item [{XC,}] ( xchar --- ) Legt ein Xchar im Dictionary ab. Auch das leicht zu implementieren: \begin{small} \begin{verbatim} : xc, ( xchar -- ) here xc!+ dp ! ; \end{verbatim} \end{small} \item [{XCHAR+}] ( xc--addr1 --- xc--addr2 ) Geht zum nächsten Xchar, ebenfalls trivial zu implementieren: \begin{small} \begin{verbatim} : xchar+ ( xc-addr1 -- xc-addr2 ) xc@+ drop ; \end{verbatim} \end{small} Es gibt da noch ein XCHAR--, das nicht ganz so leicht zu implementieren ist, aber sehr nützlich für den Zeileneditor. Bei UTF--8 sucht man rückwärts nach etwas, was entweder ASCII oder größer \$C0 ist. \item [{XKEY}] ( --- xchar ) Liest ein Xchar vom Terminal. Auch hier ist die Implementierung Encoding--abhängig. \begin{small} \begin{verbatim} : xkey ( -- xchar) key dup $80 u< IF EXIT THEN $7F and $40 >r BEGIN dup r@ and WHILE r@ xor 6 lshift r> 5 lshift >r >r key $3F and r> or REPEAT r> drop ; \end{verbatim} \end{small} \item [{XKEY?}] ( --- flag ) Liefert true zurück, wenn ein komplettes Xchar im Input--Buffer des Terminals angelangt ist. Das heißt, man muss Buffering implementieren. Ich überlasse das als Übung dem Leser, und überlege mir, ob man XKEY? auf dem Controller wirklich braucht. \item [{XEMIT}] ( xchar --- ) Gibt ein Xchar auf dem Terminal aus. Das kann man jetzt wieder direkt implementieren: \begin{small} \begin{verbatim} : xemit ( xchar -- ) xc-buf xc!+ xc-buf tuck - type ; \end{verbatim} \end{small} \end{description} \end{multicols} \vfill \begin{figure} \begin{center} \includegraphics[height=5.7cm]{2011-03/2011-05-20_15-34-05} \end{center} \caption{Das Thema Schreibrichtung ist nichts für Microcontroller} \end{figure} %\end{document}