%% 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}