%% LyX 1.4.0pre3 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[latin1]{inputenc}
\setcounter{secnumdepth}{0}
\setcounter{tocdepth}{0}

\makeatletter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
\newenvironment{lyxcode}
{\begin{list}{}{
\setlength{\rightmargin}{\leftmargin}
\setlength{\listparindent}{0pt}% needed for AMS classes
\raggedright
\setlength{\itemsep}{0pt}
\setlength{\parsep}{0pt}
\normalfont\ttfamily}%
 \item[]}
{\end{list}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.
\usepackage{multicol}

\usepackage{babel}
\makeatother
\begin{document}

\title{Forth und UTF–8}


\author{Bernd Paysan}


\date{Forth--Tagung 2005}

\maketitle
\begin{multicols}{2}


\section{Was ist UTF--8}

UTF--8 ist ein von Ken Thompson entwickeltes Encoding für den Unicode--Zeichensatz,
der sich in der Unix--Welt durchgesetzt hat. UTF--8 hat folgende Eigenschaften:

\begin{itemize}
\item Kompatibel mit ASCII
\item Zeichen variabler Länge
\item Nächstes und vorheriges Zeichen jederzeit erkennbar
\end{itemize}
Mit variablen Zeichenlängen kann Forth nicht von Haus aus umgehen.
Das XCHAR--Wordset ist deshalb ein Vorschlag, der eine Umstellung
von Forth--Programmen in einer UTF--8--Umgebung möglich macht. Auch
andere Codierungen mit variabler Länge sind implementierbar.

bigFORTH und die nächste Version von Gforth implementieren diesen
Vorschlag.


\subsection{UTF--8 Encodings}

Die Länge eines UTF--8--Zeichens erkennt man am ersten Byte.

\begin{description}
\item [{7~Bit}] \texttt{0xxxxxxx}
\item [{11~Bit}] \texttt{110xxxxx 10xxxxxx}
\item [{16~Bit}] \texttt{1110xxxx 10xxxxxx 10xxxxxx}
\item [{21~Bit}] \texttt{11110xxx 10xxxxxx 10xxxxxx 10xxxxxx}
\item [{26~Bit}] \texttt{111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx}
\item [{31~Bit}] \texttt{1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
10xxxxxx}
\end{description}

\section{Forth--Befehle für erweiterte Zeichen}

Forth--Befehle auf Zeichenebene:

\begin{description}
\item [{XC--SIZE}] \texttt{( xc -{}- n )} gibt die Länge eines Unicode--Zeichens
in Bytes zurück
\end{description}
\begin{lyxcode}
base~@~hex

80~Value~maxascii

:~xc-size~(~xc~-{}-~n~)

~~~~dup~~~~~~maxascii~u<~IF

~~~~~~~drop~1~~EXIT

~~~~THEN~\textbackslash{}~special~case~ASCII

~~~~\$800~~2~>r

~~~~BEGIN~~2dup~u>=~~WHILE

~~~~~~~5~lshift~r>~1+~>r

~~~~~~~dup~0=~UNTIL~~THEN

~~~~2drop~r>~;
\end{lyxcode}
\begin{description}
\item [{XC@+}] \texttt{( xcaddr -{}- xcaddr' u )} Entspricht COUNT für
XCHAR--Zeichen
\end{description}
\begin{lyxcode}
:~xc@+~(~xcaddr~-{}-~xcaddr'~u~)

~~~~count~~dup~maxascii~u<~IF

~~~~~~~EXIT

~~~~THEN~~\textbackslash{}~special~case~ASCII

~~~~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{lyxcode}
\begin{description}
\item [{XC!+}] \texttt{( xc xcaddr -{}- xcaddr' )} Abspeichern eines Unicode--Zeichens
als XCHAR
\end{description}
\begin{lyxcode}
:~xc!+~(~xc~xcaddr~-{}-~xcaddr'~)

~~~~over~maxascii~u<~IF

~~~~~~~tuck~c!~char+~~EXIT

~~~~THEN~\textbackslash{}~special~case~ASCII

~~~~>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{lyxcode}
\begin{description}
\item [{XC!+?}] \texttt{( xc xcaddr u -{}- xcaddr' u' flag )} Abspeichern
eines Unicode--Zeichens als XCHAR mit Prüfung, ob es im Rest des Strings
Platz hat.
\end{description}
\begin{lyxcode}
:~xc!+?~(~xc~xcaddr~u~-{}-~xcaddr'~u'~flag~)

~~~~>r~over~xc-size~r@~over~u<~IF

~~~~~~~~(~xc~xc-addr1~len~r:~u1~)

~~~~~~~~\textbackslash{}~not~enough~space

~~~~~~~~drop~nip~r>~false

~~~~ELSE

~~~~~~~~>r~xc!+~r>~r>~swap~-~true

~~~~THEN~;
\end{lyxcode}
\begin{description}
\item [{XCHAR+}] \texttt{( xaddr -{}- xaddr' )} Vorwärts zum nächsten XCHAR--Zeichen
\end{description}
\begin{lyxcode}
:~xchar+~(~xcaddr~-{}-~xcaddr'~)

~~~~xc@+~drop~;
\end{lyxcode}
\begin{description}
\item [{XCHAR--}] \texttt{( xaddr -{}- xaddr' )} Rückwärts zum vorherigen
XCHAR--Zeichen
\end{description}
\begin{lyxcode}
:~xchar-~(~xcaddr~-{}-~xcaddr'~)

~~~~BEGIN~~1~chars~-~dup~c@~C0~and

~~~~~~~~~~~maxascii~<>~~UNTIL~;
\end{lyxcode}
\begin{description}
\item [{XSTRING+}] \texttt{( xaddr u -{}- xaddr' u' )} Vorwärts zum nächsten
XCHAR--Zeichen am Ende eines Strings
\end{description}
\begin{lyxcode}
:~xstring+~(~xcaddr~u~-{}-~xcaddr~u'~)

~~~~over~+~xchar+~over~-~;
\end{lyxcode}
\begin{description}
\item [{XSTRING--}] \texttt{( xaddr u -{}- xaddr' u' )} Rückwärts zum vorherigen
XCHAR--Zeichen am Ende eines Strings
\end{description}
\begin{lyxcode}
:~xstring-~(~xcaddr~u~-{}-~xcaddr~u'~)

~~~~over~+~xchar-~over~-~;
\end{lyxcode}
\begin{description}
\item [{+XSTRING}] \texttt{( xaddr u -{}- xaddr' u' )} Vorwärts zum nächsten
XCHAR--Zeichen am Anfang eines Strings
\end{description}
\begin{lyxcode}
:~+xstring~(~xc-addr1~u1~-{}-~xc-addr2~u2~)

~~~~over~dup~xchar+~swap~-~/string~;
\end{lyxcode}
\begin{description}
\item [{--XSTRING}] \texttt{( xaddr u -{}- xaddr' u' )} Rückwärts zum vorherigen
XCHAR--Zeichen am Anfang eines Strings
\end{description}
\begin{lyxcode}
:~-xstring~(~xc-addr1~u1~-{}-~xc-addr2~u2~)

~~~~over~dup~xchar-~swap~-~/string~;
\end{lyxcode}
\begin{description}
\item [{X--WIDTH}] \texttt{( xcaddr u -{}- n )} Berechnung des Platzes
auf einem fixed--width--Terminal --- die Tabelle des zugrundeliegenden
WCWIDTH lasse ich hier aber weg.
\end{description}
\begin{lyxcode}
:~wcwidth~(~xc~-{}-~n~)

~~~~wc-table~\#wc-table~over~+~swap~?DO

~~~~~~~~dup~I~2@~within~IF

~~~~~~~~~~~I~2~cells~+~@~~UNLOOP~EXIT

~~~~~~~~THEN

~~~~3~cells~+LOOP~~1~;



:~x-width~(~xcaddr~u~-{}-~n~)

~~~~0~rot~rot~over~+~swap~?DO

~~~~~~~~I~xc@+~swap~>r~wcwidth~+

~~~~r>~I~-~+LOOP~;
\end{lyxcode}
Forth--Befehle für's Terminal

\begin{description}
\item [{XKEY}] \texttt{( -{}- xc )} Lesen eines XCHAR--Zeichens vom Terminal
\end{description}
\begin{lyxcode}
:~xkey~(~-{}-~xc~)

~~~~key~dup~maxascii~u<~IF

~~~~~~~~EXIT

~~~~THEN~~\textbackslash{}~special~case~ASCII

~~~~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{lyxcode}
\begin{description}
\item [{XEMIT}] \texttt{( xc -{}- )} Schreiben eines XCHAR--Zeichens auf's
Terminal
\end{description}
\begin{lyxcode}
:~xemit~(~xc~-{}-~)

~~~~dup~maxascii~u<~IF

~~~~~~~emit~~EXIT

~~~~THEN~\textbackslash{}~special~case~ASCII

~~~~0~swap~~3F

~~~~BEGIN~~2dup~u>~~WHILE

~~~~~~~~~~~2/~>r~~dup~3F~and~80~or

~~~~~~~~~~~swap~6~rshift~r>

~~~~REPEAT~~7F~xor~2{*}~or

~~~~BEGIN~~~dup~80~u<~0=~WHILE

~~~~~~~~~~~~emit~~REPEAT~~drop~;
\end{lyxcode}
CHAR und {[}CHAR] müssen noch angepasst werden:

\begin{lyxcode}
:~char~~(~\char`\"{}name\char`\"{}~-{}-~xc~)

~~~~bl~word~count~drop~xc@+~nip~;

:~{[}char]~(~\char`\"{}name\char`\"{}~-{}-~rt:xc~)

~~~~char~postpone~Literal~;~immediate
\end{lyxcode}
\begin{itemize}
\item Kein extra TYPE nötig, wohl aber ein angepasstes ACCEPT.
\item Automatische Anpassung, was ein XC ist abhängig von den Umgebungsvariablen,
bei ISO--Latin bleibt ein XC ein Byte.
\end{itemize}
\begin{lyxcode}
80~Constant~utf-8

100~Constant~iso-latin-1



:~set-encoding~~to~maxascii~;

:~get-encoding~~maxascii~;



base~!
\end{lyxcode}

\section{Weitere Forth--Befehle nötig?}

Beim Zugriff auf Dateien mit verschiedenen Encodings will man eventuell
eine transparente Umcodierung.

Beim Wechsel des Systems zwischen verschiedenen Encodings (Wörter,
eincompilierte Strings mit Umlauten) besteht ebenfalls ein prinzipielles
Problem.

Lösungen:

\begin{itemize}
\item Ignorieren? Wir gehen einfach davon aus, dass das System erst mal
nur mit ASCII gefüllt wurde, und dann nur eine Umgebung (UTF--8 oder
ISO--LATIN) verwendet wird; kein Mix erlaubt.
\item Recodieren von Dateien in READ--LINE und WRITE--LINE?
\end{itemize}
\end{multicols}
\end{document}
