<!--
<!doctype linuxdoc system>
-->
<!doctype linuxdoctr system>

<!-- &dollar;Id: Lex-YACC-HOWTO.sgml,v 1.2 2002/07/22 14:02:09 gferg Exp $
 -->

<article>

<!-- Title information -->
<title>Lex and YACC primer/HOWTO

<author>PowerDNS BV (bert hubert &lt;bert@powerdns.com&gt;)&nl;
<date>v0.8 &dollar;Date: 2002/07/22 14:02:09 $

<!-- 日本語版 -->
<trans>大西 大樹 (daiki onishi &lt;onishi@mbc.nifty.com&gt;)&nl;
<tdate>v0.8j 2003/02/08

<abstract>

<!--
This document tries to help you get started using Lex and YACC
-->

本ドキュメントは Lex と YACC の基本的な使い方について記述します

</abstract>

<!-- Table of contents -->
<toc>

<!-- Begin the document -->

<sect>

<!--
Introduction
-->

イントロダクション

<p>

<!--
Welcome, gentle reader. 
-->

ようこそ、高貴なる読者のみなさん

<p>

<!--
If you have been programming for any length of time in a Unix environment,
you will have encountered the mystical programs Lex &amp; YACC, or as they
are known to GNU/Linux users worldwide, Flex &amp; Bison, where Flex is a
Lex implementation by Vern Paxon and Bison the GNU version of YACC. We will
call these programs Lex and YACC throughout - the newer versions are
upwardly compatible, so you can use Flex and Bison when trying our examples.
-->

Unix 環境で、ある程度プログラミング経験を積まれている方なら、Lex &amp;
YACC、もしくは GNU/Linux ユーザの間で Flex &amp; Bison として知られて
いる、神秘的なプログラムをご存知のことと思います。Flex とは、Vern
Paxon による Lex 実装であり、Bison とは GNU 版 YACC です。以下、断りの
ない限りこれらを Lex &amp; YACC と呼ぶことにします - Flex &amp; Bison 
は、Lex &amp; YACC と上位互換にあるので、本ドキュメントのサンプルもそ
のまま動作します。

<!--
These programs are massively useful, but as with your C compiler, their
manpage does not explain the language they understand, nor how to use them.
YACC is really amazing when used in combination with Lex, however, the Bison
manpage does not describe how to integrate Lex generated code with your
Bison program.
-->

これらのプログラムは、非常に利用価値の高いものです。しかし、C コンパイ
ラの man ページがそうであるように、言語仕様はもとより使い方についてす
ら満足な記述がありません。YACC は Lex と組み合わせて使うと、高い効果が
得られるのですが、Bison の man ページには Lex で生成されたコードと 
Bison のプログラムを協調動作させる方法についての記述がありません。

<sect1>
<!--
What this document is NOT
-->
本ドキュメントに含まれないもの
<p>

<!--
There are several great books which deal with Lex &amp; YACC. By all means
read these books if you need to know more. They provide far more information
than we ever will. See the 'Further Reading' section at the end. This
document is aimed at bootstrapping your use of Lex
&amp; YACC, to allow you to create your first programs.
-->

Lex &amp; YACC については、いくつか良書があります。深く知りたいのであ
れば、是非読むことをお勧めします。本ドキュメントに書かれているより、ずっ
とたくさんの情報が得られるはずです。巻末の '関連情報' の章をご覧くださ
い。ここでは、読者が簡単なプログラムを組める程度に、Lex &amp; YACC の
基本的な使い方を解説することに内容をとどめます。

<!--
The documentation that comes with Flex and BISON is also excellent, but no
tutorial. They do complement my HOWTO very well though. They too are
referenced at the end.
-->

Flex と BISON に付属してくるドキュメントも良いのですが、チュートリアル
がありません。この HOWTO の足りない部分を補完する分には有用ですが。こ
れに関しても、巻末の関連情報の章をご覧ください。

<!--
I am by no means a YACC/Lex expert. When I started writing this document, I
had exactly two days of experience. All I want to accomplish is to make
those two days easier for you.
-->

筆者は YACC/Lex のエキスパートではありません。このドキュメントを書き始
めた頃でも、ちょうど二日の経験しかありませんでした。筆者の願いは、この
二日間を皆さんにとって、少しでも楽なものにしてあげたいということに尽き
ます。

<!--
In no way expect the HOWTO to show proper YACC and Lex style. Examples
have been kept very simple and there may be better ways to write them. If
you know how to, please let me know.
-->

ここに例示される、YACC と Lex のコーディングスタイルが常に最も適切であ
るとは限りません。コード例はシンプルにするよう努めましたが、より良い書
き方があるかもしれません。お気づきの点があれば是非、お教えください。

<sect1>
<!--
Downloading stuff 
-->
ダウンロード
<p>

<!--
Please note that you can download all the examples shown, which are in
machine readable form. See the <url name="homepage"
url="http://ds9a.nl/lex-yacc"> for details.
-->

例示されているコードは、すべて machine readable な形式でダウンロードで
きます。詳細は <url name="ホームページ" url="http://ds9a.nl/lex-yacc"> 
をご覧ください。

<sect1>
<!--
License
-->
ライセンスについて

<p>

<!--
Copyright (c) 2001 by bert hubert. This material may be
distributed only subject to the terms and conditions set forth in the Open
Publication License, vX.Y or later (the latest version is presently
available at http://www.opencontent.org/openpub/).
-->

Copyright (c) 2001 by bert hubert. この著作物の配布に関しては Open
Publication License, vX.Y またはそれ以降で定められている規約と条件に準
拠します（最新版は http://www.opencontent.org/openpub/ で入手可能です）。

<sect>
<!--
What Lex &amp; YACC can do for you
-->

Lex と YACC でできること

<p>
<!--
When properly used, these programs allow you to parse complex languages with
ease. This is a great boon when you want to read a configuration file, or
want to write a compiler for any language you (or anyone else) might have
invented.
-->

これらのプログラムを正しく利用すると、簡単に複雑な言語の構文解析ができ
るようになります。特に設定ファイルを読み込みたい時や、自分または他人が
発案した言語用のコンパイラを書きたい時などに、非常に助けとなります。

<!--
With a little help, which this document will hopefully provide, you will
find that you will never write a parser again by hand - Lex &amp; YACC are
the tools to do this.
-->

このドキュメントでは、わずかな手助けにしかならないかもしれませんが、そ
れでも、今後手作業で構文解析器 (Parser) を書いてみようとは思わなくなる
はずです - Lex &amp; YACCとはそのような作業をしてくれるツールです。

<sect1>
<!--
What each program does on its own
-->

それぞれのプログラムのやっていること

<p>
<!--
Although these programs shine when used together, they each serve a
different purpose. The next chapter will explain what each part does.
-->

これらのプログラムは、組み合わせて使うとすばらしいものですが、それぞれ
は違った目的の上に作られています。次章ではそれぞれがやっていることを説
明します。

<sect>Lex
<p>
<!--
The program Lex generates a so called `Lexer'. This is a function that takes
a stream of characters as its input, and whenever it sees a group of
characters that match a key, takes a certain action. A very simple example:
-->

Lex プログラムは '字句解析器 (Lexer)' と呼ばれるものを生成します。これ
は入力に文字列ストリームをとる関数で、キーにマッチする文字列群を見つけ
た時に、ある決まった動作をさせることができます。以下はその簡単な例です。

<tscreen><verb>
%{
#include <stdio.h>
%}

%%
stop	printf(&dquot;Stop command received\n&dquot;);
start	printf(&dquot;Start command received\n&dquot;);
%%

</verb></tscreen>

<!--
The first section, in between the %{ and %} pair is included directly in the
output program. We need this, because we use printf later on, which is
defined in stdio.h.
-->

%{ と %} の組で括られる最初のセクションは、出力プログラムでは直接イン
クルードされます。これは、stdio.h で定義されている printf が、後で必要
となるためです。

<!--
Sections are separated using '%%', so the first line of the second section
starts with the 'stop' key. Whenever the 'stop' key is encountered in the
input, the rest of the line (a printf() call) is executed.
-->

セクションは '%%' で区切られ、二つ目のセクションの第一行は 'stop' キー
で始まることになります。入力で 'stop' キーが発現した時は、残り行 (
printf() 呼び出し) が実行されます。

<!-- 
Besides 'stop', we've also defined 'start', which otherwise does mostly the
same.
-->

&dquot;stop&dquot; に加えて、ここでは &dquot;start&dquot; というほとんど同じ動作をするものも
定義しました。

<!--
We terminate the code section with '%%' again. 
-->

上記のコードセクションを '%%' で閉じます。

<!--
To compile Example 1, do this:
-->

Example 1 をコンパイルするには以下のようにします。

<tscreen><verb>
lex example1.l
cc lex.yy.c -o example1 -ll

</verb></tscreen>

<!--
<tscreen>
NOTE: If you are using flex, instead of lex, you may have to change '-ll' 
to '-lfl' in the compilation scripts. RedHat 6.x and SuSE need this, even when
you invoke 'flex' as 'lex'!
</tscreen>
-->

<tscreen>
注意 - lex の代わりに flex を使用している方は、コンパイルスクリプトの'-
ll' を '-lfl' に置き換える必要があるかもしれません。RedHat 6.x やSuSE 
では 'flex' を 'lex' として起動しているかもしれませんが、この変更が必
要です!
</tscreen>

<!--
This will generate the file 'example1'. If you run it, it waits for you to
type some input. Whenever you type something that is not matched by any of
the defined keys (ie, 'stop' and 'start') it's output again. If you 
enter 'stop' it will output 'Stop command received';
-->

以上により、'example1' というファイルが生成されたと思います。実行する
と、キーボードからの入力待ちになります。定義済みのキー ( 即ち、'stop' 
や 'start') 以外のものを入力すると、それがそのまま出力されます。'stop' 
を入力すると、'Stop command received' が出力されます。

<!--
Terminate with a EOF (^D).
-->

EOF (^D) でプログラムを終了させることができます。

<!--
You may wonder how the program runs, as we didn't define a main() function.
This function is defined for you in libl (liblex) which we compiled in with
the -ll command.
-->

main() 関数も定義されていないのに、どうやってプログラムが動いたのか不
思議に思われたかもしれません。これは、-ll コマンドでコンパイル時にリン
クした libl (liblex) が、main() 関数の定義を含んでいたからです。

<sect1>
<!--
Regular expressions in matches
-->

正規表現でのマッチ

<p>
<!--
This example wasn't very useful in itself, and our next one won't be either.
It will however show how to use regular expressions in Lex, which are
massively useful later on.
-->

上記の例は、それ自身ではあまり使えるものではありませんでした。次の例も
それほど利用価値のあるものではないのですが、後々重宝することになる、
Lex での正規表現の使い方を例示しています。

Example 2:
<tscreen><verb>
&percnt;{
#include <stdio.h>
&percnt;}

&percnt;&percnt;
[0123456789]+		printf(&dquot;NUMBER\n&dquot;);
[a-zA-Z][a-zA-Z0-9]*	printf(&dquot;WORD\n&dquot;);
&percnt;&percnt;

</verb></tscreen>

<!--
This Lex file describes two kinds of matches (tokens): WORDs and NUMBERs.
Regular expressions can be pretty daunting but with only a little work it is
easy to understand them. Let's examine the NUMBER match:
-->

この Lex ファイルでは WORD と NUMBER という、二種類のマッチ（トークン）
を記述しています。正規表現と聞くとびくついてしまう人もいるかもしれませ
んが、ちょっと勉強すればすぐに理解できるようになるものです。NUMBER に
対するマッチを見てみましょう。

[0123456789]+	

<!--
This says: a sequence of one or more characters from the group 0123456789.
We could also have written it shorter as:
-->

これは、0123456789 のどれか一文字を含む文字、または文字列が存在すると
いう意味です。以下のような簡略表記もできます。

[0-9]+

<!--
Now, the WORD match is somewhat more involved:
-->

WORD マッチはもう少し複雑になります。

[a-zA-Z][a-zA-Z0-9]*

<!--
The first part matches 1 and only 1 character that is between 'a' and 'z',
or between 'A' and 'Z'. In other words, a letter. This initial letter then
needs to be followed by zero or more characters which are either a letter or
a digit. Why use an asterisk here? The '+' signifies 1 or more matches, but
a WORD might very well consist of only one character, which we've already
matched. So the second part may have zero matches, so we write a '*'.
-->

前半部分は、'a' から 'z' または 'A' から 'Z' の間の文字列、つまりアル
ファベットのどれかという意味です。アルファベットの後には、アルファベッ
トもしくはアラビア数字がゼロ個以上続きます。アスタリスクを使っているの
は何故でしょう？ '+' というのは一個以上のマッチを表しますが、WORD は、
前半部分で既にマッチした一文字のみという可能性もあります。その場合には、
後半部分でのマッチがゼロになってしまうので、'*' とする必要があるのです。

<!--
This way, we've mimicked the behaviour of many programming languages which
demand that a variable name *must* start with a letter, but can contain
digits afterwards. In other words, 'temperature1' is a valid name, 
but '1temperature' is not.
-->

このようにして、多くのプログラミング言語が要求するような、最初の文字が
アルファベットで 始まらなくては *ならず*、その後はアラビア数字を含んで
も良いというような、変数名の規則に似せたものを作ることができました。つ
まり、'temperature1' は良いですが、'1temperature' はだめということにな
ります。

<!--
Try compiling Example 2, lust like Example 1, and feed it some text. Here is
a sample session:
-->

Example 1 でやったように、Example 2 をコンパイルしてみてください。それか
ら以下の例のようにテキストを入力してみてください。

<tscreen><verb>
$ ./example2
foo
WORD

bar
WORD

123
NUMBER

bar123
WORD

123bar
NUMBER
WORD
</verb></tscreen>

<!--
You may also be wondering where all this whitespace is coming from in the
output. The reason is simple: it was in the input, and we don't match on it
anywhere, so it gets output again.
-->

出力のホワイトスペースがどこから来たのか、不思議に思われたかもしれませ
ん。理由は簡単です。これらは、もともと入力に含まれていたものですが、マッ
チしないためそのまま出力となって現れたというだけの話です。

<!--
The Flex manpage documents its regular expressions in detail. Many people
feel that the perl regular expression manpage (perlre) is also very useful,
although Flex does not implement everything perl does.
-->

Flex の man ページには、使われている正規表現について詳しく載っています。
また、perl の正規表現の man ページ (perlre) を便利だと感じられる方々も
たくさんいます - もっとも Flex の正規表現の実装は、perl ほど完全ではあ
りませんが。

<!--
Make sure that you do not create zero length matches like '[0-9]*' - your
lexer might get confused and start matching empty strings repeatedly.
-->

&dquot;[0-9]*&dquot; のように、長さゼロのマッチは行わないように注意してください。
字句解析器が混乱してしまい、空文字列とのマッチを繰り返すようなことにな
ります。

<sect1>

<!--
A more complicated example for a C like syntax
-->

C のようなシンタックスをもつもう少し高度な例

<p>

<!--
Let's say we want to parse a file that looks like this:
-->

以下のような設定ファイルを構文解析したいとします。

<tscreen><verb>
logging {
	category lame-servers { null; };
	category cname { null; };
};

zone &dquot;.&dquot; {
        type hint;
        file &dquot;/etc/bind/db.root&dquot;;
};
</verb></tscreen>

<!--
We clearly see a number of categories (tokens) in this file:
-->

このファイル内にはいくつものカテゴリ（トークン）があるのがわかります。

<itemize>
<!--
<item> WORDs, like 'zone' and 'type'
<item> FILENAMEs, like '/etc/bind/db.root'
<item> QUOTEs, like those surrounding the filename
<item> OBRACEs, {
<item> EBRACEs, }
<item> SEMICOLONs, ;
-->

<item> &dquot;zone&dquot; や &dquot;type&dquot; などの WORD
<item> &dquot;/etc/bind/db.root&dquot; などの FILENAME
<item> ファイルネームを括っている QUOTE
<item> { を表す OBRACE
<item> } を表す EBRACE
<item> ; を表す SEMICOLON

</itemize>
<!--
The corresponding Lex file is Example 3:
-->

対応する Lex ファイルは Example 3 のようになります。

<!--
<tscreen><verb>
&percnt;{
#include <stdio.h>
&percnt;}

&percnt;&percnt;
[a-zA-Z][a-zA-Z0-9]*    printf(&dquot;WORD &dquot;);
[a-zA-Z0-9&bsol;/.-]+        printf(&dquot;FILENAME &dquot;);
&bsol;&dquot;                      printf(&dquot;QUOTE &dquot;);
&bsol;{                      printf(&dquot;OBRACE &dquot;);
&bsol;}                      printf(&dquot;EBRACE &dquot;);
;                       printf(&dquot;SEMICOLON &dquot;);
&bsol;n                      printf(&dquot;&bsol;n&dquot;);
[ &bsol;t]+                  /* ignore whitespace */;
&percnt;&percnt;
</verb></tscreen>
-->

<tscreen><verb>
&percnt;{
#include <stdio.h>
&percnt;}

&percnt;&percnt;
[a-zA-Z][a-zA-Z0-9]*    printf(&dquot;WORD &dquot;);
[a-zA-Z0-9&bsol;/.-]+        printf(&dquot;FILENAME &dquot;);
&bsol;&dquot;                      printf(&dquot;QUOTE &dquot;);
&bsol;{                      printf(&dquot;OBRACE &dquot;);
&bsol;}                      printf(&dquot;EBRACE &dquot;);
;                       printf(&dquot;SEMICOLON &dquot;);
&bsol;n                      printf(&dquot;&bsol;n&dquot;);
[ &bsol;t]+                  /* ホワイトスペースは無視 */;
&percnt;&percnt;
</verb></tscreen>

<!--
When we feed our file to the program this Lex file generates (using
example3.compile), we get:
-->

プログラムに設定ファイルを入力すると、この Lex ファイルから
（example3.compile を使って)以下のような出力が得られます。

<tscreen><verb>
WORD OBRACE 
WORD FILENAME OBRACE WORD SEMICOLON EBRACE SEMICOLON 
WORD WORD OBRACE WORD SEMICOLON EBRACE SEMICOLON 
EBRACE SEMICOLON 

WORD QUOTE FILENAME QUOTE OBRACE 
WORD WORD SEMICOLON 
WORD QUOTE FILENAME QUOTE SEMICOLON 
EBRACE SEMICOLON 
</verb></tscreen>

<!--
When compared with the configuration file mentioned above, it is clear that
we have neatly 'Tokenized' it. Each part of the configuration file has been
matched, and converted into a token.
-->

設定ファイルと見比べると、適切に 'トークン化' されたのがわかります。ファ
イルの各々の部分で、正規表現によるマッチがとられ、トークンに変換されて
います。

<!--
And this is exactly what we need to put YACC to good use.
-->

これが、YACC を活用するために必要なことなのです。

<sect1>
<!--
What we've seen
-->

おさらい

<p>
<!--
We've seen that Lex is able to read arbitrary input, and determine what each
part of the input is. This is called 'Tokenizing'.
-->

Lex は任意の入力から、それぞれの部分が何であるか決定することができる、
ということがわかりました。これを 'トークン化する' といいます。

<sect>YACC
<p>
<!--
YACC can parse input streams consisting of tokens with certain values. This
clearly describes the relation YACC has with Lex, YACC has no idea 
what 'input streams' are, it needs preprocessed tokens. While you can write your
own Tokenizer, we will leave that entirely up to Lex.
-->

YACC は、ある値をもつトークンから構成される、入力ストリームの構文解析
をすることができます。このことは、Lex に対する YACC の関係を、はっきり
と示しています。YACC はそもそも '入力ストリーム' というものが何である
かを理解しておらず、トークン化された入力を必要とします。ご自身で字句解
析プログラムを書かれても良いですが、ここではそれは Lex に譲ることにし
ます。

<!--
A note on grammars and parsers. When YACC saw the light of day, the tool was
used to parse input files for compilers: programs. Programs written in a
programming language for computers are typically *not* ambiguous - they have
just one meaning. As such, YACC does not cope with ambiguity and will
complain about shift/reduce or reduce/reduce conflicts. More about
ambiguity and YACC &dquot;problems&dquot; can be found in 'Conflicts' chapter.
-->

文法と構文解析器について、補足しておきます。YACC は、登場したての頃は
コンパイラへの入力ファイル - つまりプログラム- の構文解析に使われてい
ました。コンピュータ向けのプログラミング言語で書かれたプログラムは、通
常曖昧なところは *なく*、意味も一つに限られています。従って、YACC は曖
昧さを許容できず、shift/reduce や reduce/reduce コンフリクトなどの警告
やエラーを出します。曖昧さと YACC 特有の &dquot;問題点&dquot; について
は、'コンフリクト' の章をご覧ください。

<sect1>
<!--
A simple thermostat controller
-->
単純な温度調節器

<p>
<!--
Let's say we have a thermostat that we want to control using a simple
language. A session with the thermostat may look like this:
-->

単純な言語を使って制御できる温度調節器があるとします。この温度調節器を
使ったやりとりは以下のようになります。

<tscreen><verb>
heat on
	Heater on!
heat off
	Heater off!
target temperature 22
	New temperature set!
</verb></tscreen>

<!--
The tokens we need to recognize are: heat, on/off (STATE), target, temperature,
NUMBER.
-->

認識しなくてはならないトークンは、heat, on/off(STATE), target,
temperature, NUMBER です。

<!--
The Lex tokenizer (Example 4) is:
-->

この字句解析器を Lex で作ると (Example 4) 

<!--
<tscreen><verb>
&percnt;{
#include <stdio.h>
#include &dquot;y.tab.h&dquot;
&percnt;}
&percnt;&percnt;
[0-9]+                  return NUMBER;
heat                    return TOKHEAT;
on|off                  return STATE;
target                  return TOKTARGET;
temperature             return TOKTEMPERATURE;
&bsol;n                      /* ignore end of line */;
[ &bsol;t]+                  /* ignore whitespace */;
&percnt;&percnt;
</verb></tscreen>
-->

<tscreen><verb>
&percnt;{
#include <stdio.h>
#include &dquot;y.tab.h&dquot;
&percnt;}
&percnt;&percnt;
[0-9]+                  return NUMBER;
heat                    return TOKHEAT;
on|off                  return STATE;
target                  return TOKTARGET;
temperature             return TOKTEMPERATURE;
&bsol;n                      /* 改行は無視 */;
[ &bsol;t]+                  /* ホワイトスペースは無視 */;
&percnt;&percnt;
</verb></tscreen>

<!--
We note two important changes. First, we include the file 'y.tab.h', and
secondly, we no longer print stuff, we return names of tokens. This change
is because we are now feeding it all to YACC, which isn't interested in
what we output to the screen. Y.tab.h has definitions for these tokens.
-->

二つ大きな違いがあります。一つ目は 'y.tab.h' をインクルードしているこ
とです。二つ目は、print 出力するのをやめてトークン名を返すようにしてい
るということです。これは、Lex の出力を全て YACC に入力しようとしている
からで、スクリーンに表示する意味がないからです。y.tab.h ではトークンの
定義がされています。

<!--
But where does y.tab.h come from? It is generated by YACC from the Grammar
File we are about to create. As our language is very basic, so is the grammar:
-->

y.tab.h はどこから出て来たのでしょう？これは、後で作ることになる文法ファ
イルから YACC が生成したものです。言語と同様、文法も非常に単純になって
います。

<tscreen><verb>
commands: /* empty */
        | commands command
        ;

command:
        heat_switch
        |
        target_set
        ;

heat_switch:
        TOKHEAT STATE
        {
         	printf(&dquot;&bsol;tHeat turned on or off&bsol;n&dquot;);
        }
        ;

target_set:
        TOKTARGET TOKTEMPERATURE NUMBER
        {
         	printf(&dquot;&bsol;tTemperature set&bsol;n&dquot;);
        }
        ;
</verb></tscreen>

<!--
The first part is what I call the 'root'. It tells us that we 
have 'commands', and that these commands consist of individual 'command'
parts. As you can see this rule is very recursive, because it again
contains the word 'commands'. What this means is that the program is now
capable of reducing a series of commands one by one. Read the chapter 'How
do Lex and YACC work internally' for important details on recursion.
-->

先頭の部分を、ここでは 'root' と呼ぶことにします。これは 'commands' と
いうものが定義されていて、それが個別の 'command' から構成されていると
いうことを示しています。コマンドがさらにコマンドを含んでいることから、
この規則は再帰的であると言えます。これはまた、構文解析器が連続するコマ
ンドを一つずつ還元できるようになった、ということも意味しています。再帰
については、'Lex と YACC の内部動作' の章に重要な記述があります。

<!--
The second rule defines what a command is. We support only two kinds of
commands, the 'heat_switch' and the 'target_set'. This is what the |-symbol
signifies - 'a command consists of either a heat_switch or a target_set'.
-->

その次は、コマンドを定義する規則です。ここでは、'heat_switch' と 'target_set'
という二種類のみサポートします。これは | 記号で表され、' 
コマンドが heat_switch または target_set から成る' ことを示しています。

<!--
A heat_switch consists of the HEAT token, which is simply the word 'heat',
followed by a state (which we defined in the Lex file as 'on' or 'off').
-->

heat_switch は、単に 'heat' という単語を指す HEAT トークンに、状態
(Lex ファイルで 'on' や 'off' として定義済み）を付加したものです。

<!--
Somewhat more complicated is the target_set, which consists of the TARGET
token (the word 'target'), the TEMPERATURE token (the word 'temperature')
and a number.
-->

target_set はもう少し複雑で、これは TARGET トークン ('target' という単
語)、TEMPERATURE トークン ('temperature' という単語) そして数字から構
成されています。

<sect2>
<!--
A complete YACC file
-->

YACC ファイルの全文

<p>
<!--
The previous section only showed the grammar part of the YACC file, but
there is more. This is the header that we omitted:
-->

前のセクションでは、YACC の文法部分だけでしたが、もう少し解説しておく
ことがあります。以下は省略したヘッダの部分です。

<tscreen><verb>
&percnt;{
#include <stdio.h>
#include <string.h>
 
void yyerror(const char *str)
{
 	fprintf(stderr,&dquot;error: &percnt;s&bsol;n&dquot;,str);
}
 
int yywrap()
{
 	return 1;
} 
  
main()
{
  	yyparse();
} 

&percnt;}

&percnt;token NUMBER TOKHEAT STATE TOKTARGET TOKTEMPERATURE
</verb></tscreen>

<!--
The yyerror() function is called by YACC if it finds an error. We simply
output the message passed, but there are smarter things to do. See 
the 'Further reading' section at the end.
-->

yyerror() 関数はエラーが見つかった時に、YACC から呼ばれます。ここでは
単に与えられたメッセージを出力しますが、もう少し賢いこともできます。巻
末の'関連書籍'の章をご覧ください。

<!--
The function yywrap() can be used to continue reading from another file. It
is called at EOF and you can than open another file, and return 0. Or you
can return 1, indicating that this is truly the end. For more about this,
see the 'How do Lex and YACC work internally' chapter.
-->

yywrap() 関数は、連続して他のファイルから読み続けるのに使われます。
EOF で呼ばれ、もう一つのファイルをオープンした後 0 を返します。または
1 を返して、もう読むべきファイルはないということを通知します。詳しくは'
Lex と YACC の内部動作'の章をご覧ください。

<!--
Then there is the main() function, that does nothing but set everything in
motion.
-->

それから main() 関数がありますが、これはプログラムを起動するという以外のこ
とは何もしていません。

<!--
The last line simply defines the tokens we will be using. These are output
using y.tab.h if YACC is invoked with the '-d' option.
-->

最終行は、単に使用するトークンを定義しているだけです。これらは YACC を 
-d オプションで実行した時に自動生成される y.tab.h から得られます。

<sect2>

<!--
Compiling &amp; running the thermostat controller
-->

温度調節器のコンパイルと起動

<p>
<tscreen><verb>
lex example4.l
yacc -d example4.y
cc lex.yy.c y.tab.c -o example4 

</verb></tscreen>

<!--
A few things have changed. We now also invoke YACC to compile our grammar,
which creates y.tab.c and y.tab.h. We then call Lex as usual. When
compiling, we remove the -ll flag: we now have our own main() function and
don't need the one provided by libl.
-->

いくつか以前と違う点があります。YACC を使って文法ファイルをコンパイル
することで、y.tab.c と y.tab.h を生成しています。それから普通に Lex を
呼び出しています。コンパイルする時は -ll フラグを外してください。こ
こではmain() 関数を定義しているので、libl で提供されるものを使う必要が
ありません。

<!--
<tscreen>
NOTE: if you get an error about your compiler not being able to 
find 'yylval', add this to example4.l, just beneath #include
&lt;y.tab.h&gt;:
<verb>
extern YYSTYPE yylval;
</verb>
This is explained in the 'How Lex and YACC work internally' section.
</tscreen>
-->

<tscreen>
注意 - コンパイラが 'yylval' が見つからないというエラーを出す場合は、
example4.l の #include &lt;y.tab.h&gt; の直後に、以下を記述してくださ
い。
<verb>
extern YYSTYPE yylval;
</verb>
これについては 'Lex と YACC の内部動作' の章に説明されています。
</tscreen>

<!--
A sample session:
-->

以下は、簡単な動作例です。

<tscreen><verb>
$ ./example4 
heat on
	Heat turned on or off
heat off
	Heat turned on or off
target temperature 10
	Temperature set
target humidity 20
error: parse error
$
</verb></tscreen>

<!--
This is not quite what we set out to achieve, but in the interest of keeping
the learning curve manageable, not all cool stuff can be presented at once.
-->

本当にやりたかったこととは多少ずれていますが、無理のない学習曲線を辿る
という意味でも、ここでかっこいいコードやテクニックをいっぺんに紹介する
のは避けています。

<sect1>

<!--
Expanding the thermostat to handle parameters
-->

引数を扱えるように拡張した、温度調節器

<p>

<!--
As we've seen, we now parse the thermostat commands correctly, and even flag
mistakes properly. But as you might have guessed by the weasely wording, the
program has no idea of what it should do, it does not get passed any of the
values you enter.
-->

ここまでで、温度調節器のコマンドを正しく構文解析することができるように
なっただけでなく、エラーの通知処理も適切に行えるようになりました。しか
し、（Temperature set というような）曖昧な言い回しからも想像がつくよう
に、プログラムは何をすべきか理解しておらず、ユーザから入力された値も受
け取っていません。

<!--
Let's start by adding the ability to read the new target temperature. In
order to do so, we need to learn the NUMBER match in the Lexer to convert
itself into an integer value, which can then be read in YACC.
-->

新規の設定温度値を読み込む機能を追加してみましょう。これをするためには、
字句解析器でどのように NUMBER に対するマッチがなされて、YACC で読める
ような整数値に変換されるのかを知る必要があります。

<!--
Whenever Lex matches a target, it puts the text of the match in the
character string 'yytext'. YACC in turn expects to find a value in the
variable 'yylval'. In Example 5, we see the obvious solution:
-->

Lex では、ターゲットにマッチするものがあった時、'yytext' という文字列
にマッチしたテキストを格納します。一方YACC では、数値のマッチは'
yylval' 変数の値を読むことで得られます。Example 5 はその実装です。

<!--
<tscreen><verb>
&percnt;{
#include <stdio.h>
#include &dquot;y.tab.h&dquot;
&percnt;}
&percnt;&percnt;
[0-9]+                  yylval=atoi(yytext); return NUMBER;
heat                    return TOKHEAT;
on|off                  yylval=!strcmp(yytext,&dquot;on&dquot;); return STATE;
target                  return TOKTARGET;
temperature             return TOKTEMPERATURE;
&bsol;n                      /* ignore end of line */;
[ &bsol;t]+                  /* ignore whitespace */;
&percnt;&percnt;

</verb></tscreen>
-->

<tscreen><verb>
&percnt;{
#include <stdio.h>
#include &dquot;y.tab.h&dquot;
&percnt;}
&percnt;&percnt;
[0-9]+                  yylval=atoi(yytext); return NUMBER;
heat                    return TOKHEAT;
on|off                  yylval=!strcmp(yytext,&dquot;on&dquot;); return STATE;
target                  return TOKTARGET;
temperature             return TOKTEMPERATURE;
&bsol;n                      /* 改行は無視 */;
[ &bsol;t]+                  /* ホワイトスペースは無視 */;
&percnt;&percnt;

</verb></tscreen>

<!--
As you can see, we run atoi() on yytext, and put the result in yylval, where
YACC can see it. We do much the same for the STATE match, where we compare
it to 'on', and set yylval to 1 if it is equal. Please note that having a
separate 'on' and 'off' match in Lex would produce faster code, but I wanted
to show a more complicated rule and action for a change.
-->

ご覧の通り、yytext を引数として atoi() を実行し、結果を YACC が理解で
きる yylval に格納しています。STATE についてもほとんど同様の処理を行っ
ており、'on' にマッチする文字列があれば yylval に 1 を格納しています。
Lex では 'on' と 'off' のようなマッチは別々にすると、高速なコードが生
成されるということは覚えておいてください。ここではちょっと複雑な規則と
動作をお見せしたくて、一緒にしています。

<!--
Now we need to learn YACC how to deal with this. What is called 'yylval' in
Lex has a different name in YACC. Let's examine the rule setting the new
temperature target:
-->

さて、これには YACC ではどう対応すれば良いのでしょうか。Lex の 'yylval'
は YACC では別の名前で参照されます。新規の設定温度値を記述す
る規則を見てみましょう。

<tscreen><verb>
target_set: 
	TOKTARGET TOKTEMPERATURE NUMBER
	{
         	printf(&dquot;&bsol;tTemperature set to &percnt;d&bsol;n&dquot;,$3);
	}
        ;
</verb></tscreen>

<!--
To access the value of the third part of the rule (ie, NUMBER), we need to
use $3. Whenever yylex() returns, the contents of yylval are attached to the
terminal, the value of which can be accessed with the $-construct.
-->

コマンド定義の三番目 (即ち、NUMBER) の値にアクセスするには、$3 を使い
ます。yylval の値は、yylex() から戻ってくる度にバッファの最後尾に追加
されて行き、$ コンストラクトでアクセスできるようになります。

<!--
To expound on this further, let's observe the new 'heat_switch' rule:
-->

もう少し詳しく説明するために、新しい 'heat_switch' の規則を見てみま
しょう。

<tscreen><verb>
heat_switch:
        TOKHEAT STATE
        {
         	if($2)
         	        printf(&dquot;&bsol;tHeat turned on&bsol;n&dquot;);
	 	else
                        printf(&dquot;&bsol;tHeat turned off&bsol;n&dquot;);
        }
        ;
</verb></tscreen>

<!--
If you now run example5, it properly outputs what you entered.
-->

example5 を試してみてください。入力が適切な形で出力されるはずです。

<sect1>
<!--
Parsing a configuration file
-->

設定ファイルの構文解析

<p>
<!--
Let's repeat part of the configuration file we mentioned earlier:
-->

以前に触れた設定ファイルの一部を、もう一度見てみましょう。

<tscreen><verb>
zone &dquot;.&dquot; {
        type hint;
        file &dquot;/etc/bind/db.root&dquot;;
};
</verb></tscreen>

<!--
Remember that we already wrote a Lexer for this file. Now all we need to do
is write the YACC grammar, and modify the Lexer so it returns values in 
a format YACC can understand.
-->

このファイル用の字句解析器は既に作りました。あとは YACC の文法ファイル
を作り、字句解析器の戻り値を YACC が理解できるような形式に修正するだけ
です。

<!--
In the lexer from Example 6 we see:
-->

Example 6 の 字句解析器から以下のことがわかります。

<!--
<tscreen><verb>
&percnt;{
#include <stdio.h>
#include &dquot;y.tab.h&dquot;
&percnt;}

&percnt;&percnt;

zone			return ZONETOK;
file			return FILETOK;
[a-zA-Z][a-zA-Z0-9]*    yylval=strdup(yytext); return WORD;
[a-zA-Z0-9&bsol;/.-]+        yylval=strdup(yytext); return FILENAME;
&bsol;&dquot;                      return QUOTE;
&bsol;{                      return OBRACE;
&bsol;}                      return EBRACE;
;                       return SEMICOLON;
&bsol;n                      /* ignore EOL */;
[ &bsol;t]+                  /* ignore whitespace */;
&percnt;&percnt;

</verb></tscreen>
-->

<tscreen><verb>
&percnt;{
#include <stdio.h>
#include &dquot;y.tab.h&dquot;
&percnt;}

&percnt;&percnt;

zone			return ZONETOK;
file			return FILETOK;
[a-zA-Z][a-zA-Z0-9]*    yylval=strdup(yytext); return WORD;
[a-zA-Z0-9&bsol;/.-]+        yylval=strdup(yytext); return FILENAME;
&bsol;&dquot;                      return QUOTE;
&bsol;{                      return OBRACE;
&bsol;}                      return EBRACE;
;                       return SEMICOLON;
&bsol;n                      /* EOLを無視 */;
[ &bsol;t]+                  /* ホワイトスペースを無視 */;
&percnt;&percnt;

</verb></tscreen>

<!--
If you look carefully, you can see that yylval has changed! We no longer
expect it to be an integer, but in fact assume that it is a char *. In the
interest of keeping things simple, we invoke strdup and waste a lot of
memory. Please note that this may not be a problem in many areas where you
only need to parse a file once, and then exit.
-->

注意深く見てみると、yylval が違うことに気づいたでしょう! 整数値である
ことすら期待していませんし、実際 char * であると仮定しています。問題を
簡単にするために、メモリを浪費するのも構わず strdup を実行してみます。
ひとつのファイルを一度だけパースして終了、というような一般的な用途にお
いては、これで問題ないということを覚えておいてください。

<!--
We want to store character strings because we are now mostly dealing with
names: file names and zone names. In a later chapter we will explain how to
deal with multiple types of data.
-->

ここではファイル名やゾーン名のような名前を最も頻繁に扱うので、それらを
文字列として格納したいとします。データの複数の型の扱い方については後述
します。

<!--
In order to tell YACC about the new type of yylval, we add this line to the
header of our YACC grammar:
-->

YACC に新しい型の yylval を教えてやるには、YACC の文法ファイルの先頭に
以下を追加します。

<verb>#define YYSTYPE char *</verb>

<!--
The grammar itself is again more complicated. We chop it in parts to make it
easier to digest.
-->

文法自体は更に複雑なものになっています。理解しやすいように分割してみま
す。

<tscreen><verb>
commands:
	|	 
	commands command SEMICOLON
	;


command:
	zone_set 
	;

zone_set:
	ZONETOK quotedname zonecontent
	{
		printf(&dquot;Complete zone for '&percnt;s' found&bsol;n&dquot;,$2);
	}
	;

</verb></tscreen>

<!--
This is the intro, including the aforementioned recursive 'root'. Please
note that we specify that commands are terminated (and separated) by ;'s. We
define one kind of command, the 'zone_set'. It consists of the ZONE token
(the word 'zone'), followed by a quoted name and the 'zonecontent'. This
zonecontent starts out simple enough:
-->

これは、上述の再帰的な 'root' を含む導入部分です。コマンドが ; で終端
されて（そして区切られて）いることに留意してください。ここでは 'zone_set'
という、コマンドのみ定義します。このコマンドは ZONE トーク
ン（ 'zone' という単語）と、それに続く引用符で括られた名前、それに 'zonecontent'
から成ります。まずはとっかかり易い zonecontent ですが -

<tscreen><verb>
zonecontent:
	OBRACE zonestatements EBRACE 

</verb></tscreen>

<!--
It needs to start with an OBRACE, a {. Then follow the zonestatements,
followed by an EBRACE, }.
-->

これは { で表される OBRACE で始まります。それから zonestatements、そし
て } で表される EBRACE と続きます。

<tscreen><verb>
quotedname:
        QUOTE FILENAME QUOTE
        {
         	$$=$2;
        }
</verb></tscreen>

<!--
This section defines what a 'quotedname' is: a FILENAME between QUOTEs.
Then it says something special: the value of a quotedname token is the value
of the FILENAME. This means that the quotedname has as its value the
filename without quotes.
-->

このセクションは 'quotedname' を定義しています。QUOTE に挟まれた
FILENAME という意味ですが、ちょっと特殊なのは、quotedname というトーク
ンの値が FILENAME の値に等しいということです。つまり、quotedname はファ
イル名から引用符を除いたものであるという意味です。

<!--
This is what the magic '$$=$2;' command does. It says: my value is the value
of my second part. When the quotedname is now referenced in other rules, and
you access its value with the $-construct, you see the value that we set
here with $$=$2.
-->

これは魔法の '$$=$2' コマンドがやってくれることで、自身の値は自身の二
番目の部位の値であるということを指します。他の文法規則でも参照されて
いる quotedname に $ コンストラクトでアクセスすると、ここで $$=$2 とし
て設定した値が得られます。

<!--
<tscreen>
NOTE: this grammar chokes on filenames without either a '.' or a '/'
in them.
</tscreen>
-->

<tscreen>
注意 - この文法では、ゾーンファイル名に '.' か '/' かが含まれていないと
うまく行きません。
</tscreen>

<tscreen><verb>
zonestatements:
	|
	zonestatements zonestatement SEMICOLON
	;

zonestatement:
	statements
	|
	FILETOK quotedname 
	{
		printf(&dquot;A zonefile name '&percnt;s' was encountered&bsol;n&dquot;, $2);
	}
	;

</verb></tscreen>

<!--
This is a generic statement that catches all kinds of statements within
the 'zone' block. We again see the recursiveness.
-->

これは、'zone' ブロック内のあらゆる種類の文に対応できるように一般化し
た文です。ここでも再帰性が認められます。

<tscreen><verb>
block: 
	OBRACE zonestatements EBRACE SEMICOLON
	;

statements:
	| statements statement
	;

statement: WORD | block | quotedname
</verb></tscreen>

<!--
This defines a block, and 'statements' which may be found within.
-->

これはブロックと、'文' の中に出現する '文' を定義しています。

<!--
When executed, the output is like this:
-->

実行されると、出力は以下のようになります。

<tscreen><verb>
$ ./example6
zone &dquot;.&dquot; {
        type hint;
        file &dquot;/etc/bind/db.root&dquot;;
        type hint;
};
A zonefile name '/etc/bind/db.root' was encountered
Complete zone for '.' found
</verb></tscreen>

<sect>
<!--
Making a Parser in C++
-->

C++ での構文解析器の作成

<p>

<!--
Although Lex and YACC predate C++, it is possible to generate a C++ parser.
While Flex includes an option to generate a C++ lexer, we won't be using
that, as YACC doesn't know how to deal with it directly.
-->

Lex と YACC は C++ が登場する以前からありますが、C++ で構文解析器を作
成することも可能です。Flex には C++ の 字句解析器を生成するオプション
もありますが、YACC の方にそれを直接扱う方法がないので、ここでは使用し
ません。

<!--
My preferred way to make a C++ parser is to have Lex generate a plain C
file, and to let YACC generate C++ code. When you then link your
application, you may run into some problems because the C++ code by default
won't be able to find C functions, unless you've told it that those
functions are extern &dquot;C&dquot;.
-->

筆者が C++ の構文解析器を作る際に好んで使う方法は、Lex に普通の C ファ
イルの字句解析器を出力させて、YACC に C++ の構文解析器を生成させるやり
方です。アプリケーションをリンクした時に、この方法だと問題がある場合
があります。C++ では明示的に extern &dquot;C&dquot; 宣言しない限り、デ
フォルトでは C の関数を見つけられないからです。

<!--
To do so, make a C header in YACC like this:
-->

これを回避するためには、YACC で以下のような C ヘッダを作ってください。

<tscreen><verb>
extern &dquot;C&dquot;
{
 	int yyparse(void);
 	int yylex(void);  
 	int yywrap()
 	{
 	 	return 1;
        }

}
</verb></tscreen>

<!--
If you want to declare or change yydebug, you must now do it like this:
-->

yydebug を宣言もしくは、変更したい場合はここで以下のように行ってくださ
い。

<tscreen><verb>
extern int yydebug;

main()
{
	yydebug=1;
	yyparse();
}
</verb></tscreen>

<!--
This is because C++'s One Definition Rule, which disallows multiple
definitions of yydebug.
-->

これは、C++ の '定義は一度' 規則のために必要で、yydebug の多重定義を防
ぎます。

<!--
You may also find that you need to repeat the #define of YYSTYPE in your Lex
file, because of C++'s stricter type checking. 
-->

加えて、C++ では型チェックがより厳しいので、YYSTYPE の #define を Lex 
ファイルに追記しないとだめかもしれません。

<!--
To compile, do something like this:
-->

コンパイルするには、以下のようにしてください。

<tscreen><verb>
lex bindconfig2.l
yacc &#045;&#045;verbose &#045;&#045;debug -d bindconfig2.y -o bindconfig2.cc
cc -c lex.yy.c -o lex.yy.o
c++ lex.yy.o bindconfig2.cc -o bindconfig2 
</verb></tscreen>

<!--
Because of the -o statement, y.tab.h is now called bindconfig2.cc.h, so take
that into account.
-->

-o 指定があるので、y.tab.h は bindconfig2.cc.h という名前になっている
ことにも留意してください。

<!--
To summarize: don't bother to compile your Lexer in C++, keep it in C. Make
your Parser in C++ and explain your compiler that some functions are C
functions with extern &dquot;C&dquot; statements.
-->

まとめ - 字句解析器のコンパイルは、わざわざ C++ でやろうとしないで C 
でやること。構文解析器は C++ で作り、C 関数を呼び出したい時は extern
&dquot;C&dquot; 文でコンパイラに宣言すること。

<sect>

<!--
How do Lex and YACC work internally
-->

Lex と YACC の内部動作

<p>
<!--
In the YACC file, you write your own main() function, which calls yyparse()
at one point. The function yyparse() is created for you by YACC, and ends up
in y.tab.c. 
-->

上述の YACC ファイルでは、yyparse() を呼び出す main() 関数を自作しまし
た。yyparse() 関数は YACC が自動生成してくれ、y.tab.c というファイルに
なりました。

<!--
yyparse() reads a stream of token/value pairs from yylex(), which needs to
be supplied. You can code this function yourself, or have Lex do it for you.
In our examples, we've chosen to leave this task to Lex.
-->

yyparse() は、連続して入力されるべきトークンとその値の組を、yylex() か
ら読み込みます。この関数は読者が自作されても構いませんが、Lex に作らせ
ることもできます。ここでは、Lex にやらせることにします。

<!--
The yylex() as written by Lex reads characters from a FILE * file pointer
called yyin. If you do not set yyin, it defaults to standard input. It
outputs to yyout, which if unset defaults to stdout. You can also modify
yyin in the yywrap() function which is called at the end of a file. It
allows you to open another file, and continue parsing.
-->

Lex が作成した yylex() は、yyin という FILE * 型ファイルポインタから文
字列を読み込みます。yyin はセットしない限り、デフォルトでは標準入力に
なります。出力は yyout になり、これもセットされていなければ、デフォル
トで標準出力となります。また、ファイルの最後で呼ばれる yywrap() 関数内
の yyin も変更でき、別のファイルをオープンしてパースし続けるようにする
こともできます。

<!--
If this is the case, have it return 0. If you want to end parsing at this
file, let it return 1.
-->

この場合は、0 を戻り値として返すようにしてください。パースを終了させた
い時は、1 を返すようにしてください。

<!--
Each call to yylex() returns an integer value which represents a token type.
This tells YACC what kind of token it has read. The token may optionally
have a value, which should be placed in the variable yylval.
-->

yylex() は呼ばれる度に、トークン種別を表す整数値を返します。これは 
YACC が、いままでにどんなトークンを読み込んだか見分けるのに使われます。
トークンは随意、値を持つ場合があり、その場合は yylval に値が格納されま
す。

<!--
By default yylval is of type int, but you can override that from the YACC
file by re#defining YYSTYPE.
-->

デフォルトでは、yylval は int 型ですが、YACC ファイルで再度 YYSTYPE を
#define することで、オーバーライドすることができます。

<!--
The Lexer needs to be able to access yylval. In order to do so, it must be
declared in the scope of the lexer as an extern variable. The original YACC
neglects to do this for you, so you should add the following to your lexter,
just beneath #include &lt;y.tab.h&gt;:
-->

字句解析器は、yylval にアクセスできる必要があります。そのためには、
yylval が字句解析器のスコープに対して、外部参照変数として宣言されてい
る必要があります。オリジナルの YACC は、これを自動的にしてくれないので、
以下を字句解析器の #include &lt;y.tab.h&gt; 直後に、記述する必要があり
ます。

<verb>
extern YYSTYPE yylval;
</verb>

<!--
Bison, which most people are using these days, does this for you
automatically.
-->

近年広く使われている Bison では、これを自動的にやってくれます。

<sect1>
<!--
Token values
-->
トークンの値

<p>
<!--
As mentioned before, yylex() needs to return what kind of token it
encountered, and put its value in yylval. When these tokens are defined with
the &percnt;token command, they are assigned numerical id's, starting from 256.
-->

上述したように、yylex() は出現したトークン種別を返す必要があり、値を
yylval に格納する必要があります。これらのトークンが、&percnt;token コ
マンドで定義されている場合、各々には 256 から始まる数字の id が振られ
ています。

<!--
Because of that fact, it is possible to have all ascii characters as a
token. Let's say you are writing a calculator, up till now we would have
written the lexer like this:
-->

このことから、全アスキー文字をトークンとすることも可能です。例えば、電
卓を作る場合など、これまでの経験を生かすと、以下のように字句解析器を書
けることになるでしょうか。

<tscreen><verb>
[0-9]+          yylval=atoi(yytext); return NUMBER;
[ &bsol;n]+          /* eat whitespace */;
-               return MINUS;
&bsol;*              return MULT; 
&bsol;+              return PLUS;
...
</verb></tscreen>

<!--
Our YACC grammer would then contain:
-->

YACC 文法には、以下を含むことになります：

<tscreen><verb>
	exp: 	NUMBER 
		|
		exp PLUS exp
		|
		exp MINUS exp
		|
		exp MULT exp
</verb></tscreen>

<!--
This is needlessly complicated. By using characters as shorthands for
numerical token id's, we can rewrite our lexer like this:
-->

これは無駄に複雑なだけです。数値を表すトークン id を、文字列を使って簡
略表記すると、字句解析器は以下のように書き直せます:

<verb>
[0-9]+          yylval=atoi(yytext); return NUMBER;
[ &bsol;n]+          /* eat whitespace */;
.               return (int) yytext[0];
</verb>

<!--
This last dot matches all single otherwise unmatched characters.
-->

最後のドットは、マッチしなかった文字全てを表します。

<!--
Our YACC grammer would then be:
-->

一方、YACC文法は

<tscreen><verb>
	exp: 	NUMBER 
		|
		exp '+' exp
		|
		exp '-' exp
		|
		exp '*' exp
</verb></tscreen>

<!--
This is lots shorter and also more obvious. You do not need to declare these
ascii tokens with &percnt;token in the header, they work out of the box.
-->

随分わかりやすく、また短くなりました。アスキー文字を表すトークンをヘッ
ダの &percnt;token で宣言する必要もなく、そのままで使えています。

<!--
One other very good thing about this construct is that Lex will now match
everything we throw at it - avoiding the default behaviour of echoing
unmatched input to standard output. If a user of this calculator uses a ^,
for example, it will now generate a parsing error, instead of being echoed
to standard output.
-->

このコンストラクトのもうひとつ優れたところは、入力したものはなんでも
Lex がマッチをとってくれるようになった、ということです - こうすること
で、マッチしない入力を標準出力へ吐き出すという、デフォルト動作を回避し
ています。例えば、電卓にユーザが ^ を入力すると、標準出力へそのまま表
示される代わりに構文解析エラーを出力するようになります。

<sect1>

<!--
Recursion: 'right is wrong'
-->

再帰 - '善(right=右）は悪'

<p>

<!--
Recursion is a vital aspect of YACC. Without it, you can't specify that a
file consists of a sequence of independent commands or statements. Out of
its own accord, YACC is only interested in the first rule, or the one you
designate as the starting rule, with the '&percnt;start' symbol.
-->

再帰は、YACC ではきわめて重要です。これなくしては、独立するコマンドや
文の連続からファイルが構成されている、ということが言えなくなります。つ
まり、YACC にとって最も重要なのは一番目の規則、即ち、'&percnt;start' 
シンボルで指定した、起点を示す規則のみということになります。

<!--
Recursion in YACC comes in two flavours: right and left. Left recursion,
which is the one you should use most of the time, looks like this:
-->

YACC における再帰には、2つのタイプ - 右と左 - があります。左再帰はほと
んどの場合に使うべきもので、以下のようなものです。

<verb>
commands: /* empty */
	|
	commands command
</verb>

<!--
This says: a command is either empty, or it consists of more commands,
followed by a command. They way YACC works means that it can now easily chop
off individual command groups (from the front) and reduce them.
-->

これは、コマンドが空である、もしくは複数のコマンドの後に、あるコマンド
が続くという意味です。YACC の動作からすると、これは（前方から）個々の
コマンド群を簡単に切り分けて、還元できるということを意味します。

<!--
Compare this to right recursion, which confusingly enough looks better to
many eyes:
-->

これを右再帰と比べてみると、紛らわしいですが見た目は良くなります。 

<verb>
commands: /* empty */
	|
	command commands
</verb>

<!--
But this is expensive. If used as the &percnt;start rule, it requires YACC to keep
all commands in your file on the stack, which may take a lot of memory. So
by all means, use left recursion when parsing long statements, like entire
files. Sometimes it is hard to avoid right recursion but if your statements
are not too long, you do not need to go out of your way to use left
recursion.
-->

しかし、これは処理としては高くつきます。&percnt;start 規則として使われ
た場合、YACC はファイル中の全コマンドをスタックに保持しなくてはならず、
メモリを大量に消費します。このことから、ファイル全部というような長文の
構文解析をする際は、左再帰を使用してください。時には右再帰の使用が避け
られないような状況もあるかもしれませんが、文があまりにも長すぎる場合を
除いては、左再帰以外を使う必要はないでしょう。

<!--
If you have something terminating (and therefore separating) your commands,
right recursion looks very natural, but is still expensive:
-->

コマンドを終端して（ゆえに区切って）いるものがあるような場合には、右再
帰を使うと自然な感じになりますが、処理が高くつくことにはかわりありませ
ん。

<verb>
commands: /* empty */
	|
	command SEMICOLON commands
</verb>

<!--
The right way to code this is using left recursion (I didn't invent this
either):
-->

このコードは、正しくは左再帰を使って書きます（これも筆者がでっちあげた
訳ではありません）。

<verb>
commands: /* empty */
	|
	commands command SEMICOLON
</verb>

<!--
Earlier versions of this HOWTO mistakenly used right recursion. Markus
Triska kindly informed us of this.
-->

この HOWTO の以前のバージョンでも、間違えて右再帰を使っていましたが、
Markus Triska が親切にも指摘してくれました。

<sect1>

<!--
Advanced yylval: &percnt;union
-->

より高度な yylval - &percnt;union

<p>

<!--
Currently, we need to define *the* type of yylval. This however is not
always appropriate. There will be times when we need to be able to handle
multiple data types. Returning to our hypothetical thermostat, perhaps we
want to be able to choose a heater to control, like this:
-->

ここまででは、yylval の *型そのもの* を定義する必要がありました。しか
し、これがいつも適当であるとは限りません。複数のデータ型を扱えなくては
ならないこともあるかも知れないからです。仮想温度調節器の例に戻って、制
御するべきヒーターを選びたいとしたら、以下のようになります。

<tscreen><verb>
heater mainbuiling
	Selected 'mainbuilding' heater
target temperature 23
	'mainbuilding' heater target temperature now 23
</verb></tscreen>

<!--
What this calls for is for yylval to be a union, which can hold both strings
and integers - but not simultaneously.
-->

ポイントは yylval が共用体になって、文字列と整数の両方を保持することが
できる、ということです - 同時に一緒ではありませんが。

<!--
Remember that we told YACC previously what type yylval was supposed to by by
defining YYSTYPE. We could conceivably define YYSTYPE to be a union this
way, by YACC has an easier method for doing this: the &percnt;union statement.
-->

以前、YACC に対して yylval の型を、YYSTYPE として定義していたのを思い
出してください。これは、YACC の &percnt;union 文という、より簡単な方法
で、共用体として定義することもできたのではないでしょうか。

<!--
Based on Example 4, we now write the Example 7 YACC grammar. First the
intro:
-->

Example 4 に基づいて、Example 7 の YACC 文法を書いてみます。まずはその
導入部分 -

<tscreen><verb>
&percnt;token TOKHEATER TOKHEAT TOKTARGET TOKTEMPERATURE

&percnt;union 
{
        int number;
        char *string;
}

&percnt;token <number> STATE
&percnt;token <number> NUMBER
&percnt;token <string> WORD
</verb></tscreen>

<!-- 
We define our union, which contains only a number and a string. Then
using an extended &percnt;token syntax, we explain to YACC which part
of the union each token should access.
-->

数字と文字列のみを含む、共用体を定義します。それから拡張された
&percnt;token シンタックスで、YACC に共用体のどの部分に、それぞれのトー
クンがアクセスすべきか指示しています。

<!--
In this case, we let the STATE token use an integer, as before. Same goes
for the NUMBER token, which we use for reading temperatures.
-->

この場合、以前やったように STATE トークンに int 型を割り当てます。同様
に、温度を読み取るための NUMBER トークンも割り当てます。

<!--
New however is the WORD token, which is declared to need a string.
-->

新しいのは WORD トークンで、文字列であると宣言されています。

<!--
The Lexer file changes a bit too:
-->

字句解析プログラムのファイルも、多少変更があります。

<!--
<tscreen><verb>
&percnt;{
#include <stdio.h>
#include <string.h>
#include &dquot;y.tab.h&dquot;
&percnt;}
&percnt;&percnt;
[0-9]+                  yylval.number=atoi(yytext); return NUMBER;
heater			return TOKHEATER;
heat                    return TOKHEAT;
on|off                  yylval.number=!strcmp(yytext,&dquot;on&dquot;); return STATE;
target                  return TOKTARGET;
temperature             return TOKTEMPERATURE;
[a-z0-9]+		yylval.string=strdup(yytext);return WORD;
&bsol;n                      /* ignore end of line */;
[ &bsol;t]+                  /* ignore whitespace */;
&percnt;&percnt;

</verb></tscreen>
-->

<tscreen><verb>
&percnt;{
#include <stdio.h>
#include <string.h>
#include &dquot;y.tab.h&dquot;
&percnt;}
&percnt;&percnt;
[0-9]+                  yylval.number=atoi(yytext); return NUMBER;
heater			return TOKHEATER;
heat                    return TOKHEAT;
on|off                  yylval.number=!strcmp(yytext,&dquot;on&dquot;); return STATE;
target                  return TOKTARGET;
temperature             return TOKTEMPERATURE;
[a-z0-9]+		yylval.string=strdup(yytext);return WORD;
&bsol;n                      /* 改行は無視 */;
[ &bsol;t]+                  /* ホワイトスペースは無視 */;
&percnt;&percnt;

</verb></tscreen>

<!--
As you can see, we don't access the yylval directly anymore, we add a suffix
indicating which part we want to access. We don't need to do that in the
YACC grammar however, as YACC performs the magic for us:
-->

お気づきになったように、もう yylval そのものには直接アクセスしておらず、
アクセスしたい部分を示すのに、サフィックスを付加しています。YACC には
以下のような魔法があるので、YACC 文法ではこれは不要です。

<tscreen><verb>
heater_select:
        TOKHEATER WORD
	{
	 	printf(&dquot;&bsol;tSelected heater '&percnt;s'&bsol;n&dquot;,$2);
        	heater=$2;
	}
        ;
</verb></tscreen>

<!--
Because of the &percnt;token declaration above, YACC automatically picks 
the 'string' member from our union. Note also that we store a copy of $2,
which is later used to tell the user which heater he is sending commands to:
-->

前述の &percnt;token 宣言のおかげで、YACC は自動的に共用体から '文字列' 
メンバを読み取ってくれています。また、ここでは後で、コマンドの送り先に
なっているヒーターをユーザに通知するのに使われる、$2 のコピーも格納し
ています。

<tscreen><verb>
target_set:
        TOKTARGET TOKTEMPERATURE NUMBER
        {
	 	printf(&dquot;&bsol;tHeater '&percnt;s' temperature set to &percnt;d&bsol;n&dquot;,heater,$3);
  	}
	;
</verb></tscreen>

<!--
For more details, read example7.y.
-->

詳細は example7.y を参照ください。

<sect>

<!--
Debugging
-->

デバッグ

<p>
<!--
Especially when learning, it is important to have debugging facilities.
Luckily, YACC can give a lot of feedback. This feedback comes at the cost of
some overhead, so you need to supply some switches to enable it.
-->

プログラムを、動かしながら学ぶような時は特に、デバッグ機能があること
が重要になります。幸運にもYACCは、多数のフィードバックを返す機能を持っ
ています。この機能はいくらかオーバーヘッドを必要とするので、使用にあたっ
ては幾つかのスイッチをイネーブルにする必要があります。

<!-- 
When compiling your grammar, add &#045;&#045;debug and
&#045;&#045;verbose to the YACC commandline. In your grammar C
heading, add the following:
-->

文法をコンパイルする時は、YACC のコマンドラインに、&#045;&#045;debug 
や &#045;&#045;verbose をつけます。文法ファイルの C ヘッダ部には、以下
を付加します。

	int yydebug=1;

<!--
This will generate the file 'y.output' which explains the state machine that
was created.
-->

これは 'y.output' という、出力されたステートマシンを説明するファイルを
生成します。

<!--
When you now run the generated binary, it will output a *lot* of what is
happening. This includes what state the state machine currently has, and
what tokens are being read.
-->

生成されたバイナリを実行すると、このファイルは、現在起こっていることに
ついて、*非常にたくさんの* 情報を出力してくれます。これには、ステート
マシンがどんなステートを保有しているのか、どんなトークンが読み込まれて
いるのか等の情報も含まれます。

<!--
Peter Jinks wrote a page on <URL
URL=&dquot;http://www.cs.man.ac.uk/~pjj/cs2121/debug.html&dquot; name=&dquot;debugging&dquot;> which
contains some common errors and how to solve them.
-->

Peter Jinks は<URL
URL="http://www.cs.man.ac.uk/~pjj/cs2121/debug.html" name="debugging"> 
によくあるエラーや、エラーへの対処の仕方などを載せています。

<sect1>

<!--
The state machine
-->

ステートマシン

<p>

<!--
Internally, your YACC parser runs a so called 'state machine'. As the name
implies, this is a machine that can be in several states. Then there are
rules which govern transitions from one state to another. Everything starts
with the so called 'root' rule I mentioned earlier.
-->

YACC で生成した構文解析器は、内部的には 'ステートマシン' というものを
実行しています。名前が示すように、これは、いくつかのステート（状態）を
とり得るマシン（機械）のことです。どのステートからどのステートへ遷移す
るかを決定する規則、というのも存在します。全ては筆者が前述した、いわゆ
る 'root' 規則が起点となります。

<!--
To quote from the output from the Example 7 y.output:
-->

Example 7 の y.output からの出力を引用すると -

<tscreen><verb>
state 0

    ZONETOK     , and go to state 1

    $default    reduce using rule 1 (commands)

    commands    go to state 29
    command     go to state 2
    zone_set    go to state 3
</verb></tscreen>

<!--
By default, this state reduces using the 'commands' rule. This is the
aforementioned recursive rule that defines 'commands' to be built up from
individual command statements, followed by a semicolon, followed by possibly
more commands.
-->

このステートは、デフォルトでは 'commands' 規則を用いて還元します。これ
は、前述した再帰に関する規則であり、個々のコマンド文、セミコロン、更に
続くコマンドから構成される 'commands' を定義しています。

<!--
This state reduces until it hits something it understands, in this case, a
ZONETOK, ie, the word 'zone'. It then goes to state 1, which deals further
with a zone command:
-->

このステートは、解釈できるトークン - この場合 ZONETOK 即ち 'zone' とい
う単語 - に到達するまで還元します。それから、ステート 1 へ遷移し、zone 
コマンドをさらに詳しく処理します。

<tscreen><verb>
state 1

    zone_set  ->  ZONETOK . quotedname zonecontent   (rule 4)

    QUOTE       , and go to state 4

    quotedname  go to state 5
</verb></tscreen>

<!--
The first line has a '.' in it to indicate where we are: we've just seen a
ZONETOK and are now looking for a 'quotedname'. Apparently, a quotedname
starts with a QUOTE, which sends us to state 4.
-->

最初の行は現在の場所を示す '.' を含んでいます - ZONETOK は既に見つかっ
たので、次に 'quotedname' を探しています。quotedname は QUOTE で始まる
ので、ステート 4 に遷移することになります。

<!--
To follow this further, compile Example 7 with the flags mentioned in the
Debugging section.
-->

以上についてもう少し掘り下げたい方は、Example 7 をデバッグの章で触れた
フラグを付けてコンパイルしてみてください。

<sect1>

<!--
Conflicts: 'shift/reduce', 'reduce/reduce' 
-->

コンフリクト: 'shift/reduce', 'reduce/reduce' 

<p>
<!--
Whenever YACC warns you about conflicts, you may be in for trouble. Solving
these conflicts appears to be somewhat of an art form that may teach you a
lot about your language. More than you possibly would have wanted to know.
-->

YACC がコンフリクトについて警告を出す時は、何か問題がある時でしょう。
コンフリクトを解決する作業には、ときに職人芸のような特殊さがあり、あな
たの使用している言語について多くのことを教えてくれることでしょう - そ
れもあなたが知りたかったこと以上のことを。

<!--
The problems revolve around how to interpret a sequence of tokens. Let's
suppose we define a language that needs to accept both these commands:
-->

問題は、連続するトークンをどう解釈するか、という点を中心に起こります。
以下の二つのコマンドを受け付ける必要がある言語を、定義するとしましょう。

<tscreen><verb>
	delete heater all
	delete heater number1
</verb></tscreen>

<!--
To do this, we define this grammar:
-->

これをするには、以下の文法定義が必要です。

<tscreen><verb>
	delete_heaters:
		TOKDELETE TOKHEATER mode
		{
			deleteheaters($3);
		}
	
	mode:	WORD

	delete_a_heater:
		TOKDELETE TOKHEATER WORD
		{
			delete($3);
		}
</verb></tscreen>

<!--
You may already be smelling trouble. The state machine starts by reading the
word 'delete', and then needs to decide where to go based on the next token.
This next token can either be a mode, specifying how to delete the heaters,
or the name of a heater to delete.
-->

もう問題の臭いがしてきましたね。ステートマシンは 'delete' という単語を
読むことから始めて、次のトークンが何であるかによって、遷移先を決定する
必要があります。次のトークンというのは、ヒーターの削除方法を指定するモー
ド、もしくは削除すべきヒーターの名前です。

<!--
The problem however is that for both commands, the next token is going to be
a WORD. YACC has therefore no idea what to do. This leads to 
a 'reduce/reduce' warning, and a further warning that the 'delete_a_heater'
node is never going to be reached.
-->

問題は両方のコマンドにとって、次のトークンが WORD になるということです。
YACC は、この場合どうして良いかわかりません。これが 'reduce/reduce'、
更には 'delete_a_heater' ノードに決して達することがない、という警告に
なります。

<!--
In this case the conflict is resolved easily (ie, by renaming the first
command to 'delete heaters all', or by making 'all' a separate token), but
sometimes it is harder. The y.output file generated when you pass yacc the
&dquot;&#045;&#045;verbose flag can be of tremendous help.
-->

この場合のコンフリクトは、簡単に解決できますが（最初のコマンド名を'
delete heaters all' に変更したり、'all' を独立したトークンとして定義す
るなど）、もっと複雑になることもあります。&#045;&#045;verbose フラグを
付加してyaccを通すと生成される y.output ファイルは、そんな時に非常に助
けとなります。

<sect>
<!--
Further reading
-->

関連情報

<p>
<!--
GNU YACC (Bison) comes with a very nice info-file (.info) which documents
the YACC syntax very well. It mentions Lex only once, but otherwise it's
very good. You can read .info files with Emacs or with the very nice 
tool 'pinfo'. It is also available on the GNU site: 
<URL name="BISON Manual" URL="http://www.gnu.org/manual/bison/">.
-->

GNU YACC (Bison) には、YACC のシンタックスを詳しく記述したすばらしい 
info ファイル (.info) が付属してきます。Lex は一度しか触れられていませ
んが、その点を除けば優れています。.info ファイルは Emacs や 'pinfo' と
いった、使い勝手の良いツールで読むことができます。以下の GNU サイトで
も入手可能です：<URL name="BISON Manual"
URL="http://www.gnu.org/manual/bison/">.

<!--
Flex comes with a good manpage which is very useful if you already
have a rough understanding of what Flex does. The
<URL name="Flex Manual" URL="http://www.gnu.org/manual/flex/"> is also
available online.
-->

Flex には優れた man ページが付属してきます。Flex で何ができるか、ざっ
とでも理解している人には、とても有用でしょう。<URL name="Flex Manual"
URL="http://www.gnu.org/manual/flex/"> もオンラインで入手可能です。

<!--
After this introduction to Lex and YACC, you may find that you need more
information. I haven't read any of these books yet, but they sound good:
-->

この Lex と YACC のイントロダクションを終えて、もう少し情報が欲しいと
思われた方もいるでしょう。以下の本は、筆者は全く読んでいませんが、タイ
トルはいい感じです -

<descrip>
<tag>Bison-The Yacc-Compatible Parser Generator</tag>

<!--
By Charles Donnelly and Richard Stallman. An <URL name="Amazon"
url="http://www.amazon.com/exec/obidos/ASIN/0595100325/qid=989165194/sr=1-2/ref=sc_b_3/002-7737249-1404015">user found it useful.
-->

Charles Donnelly and Richard Stallman によるものです。この本を気に入っ
た<URL name="Amazon"
url="http://www.amazon.com/exec/obidos/ASIN/0595100325/qid=989165194/sr=1-2/ref=sc_b_3/002-7737249-1404015"> 
ユーザもいらっしゃるようです。

<tag>Lex & Yacc</tag>

<!--
By John R. Levine, Tony Mason and Doug Brown. 
Considered to be the standard
work on this subject, although a bit dated. Reviews over at <URL name="Amazon" URL="http://www.amazon.com/exec/obidos/ASIN/1565920007/ref=sim_books/002-7737249-1404015">.
-->

John R. Levine, Tony Mason and Doug Brown によるものです。 ちょっと古
いですが、このテーマに関しては教科書的存在です。<URL name="Amazon"
URL="http://www.amazon.com/exec/obidos/ASIN/1565920007/ref=sim_books/002-7737249-1404015">
にレビューがあります。

<tag>Compilers : Principles, Techniques, and Tools</tag>

<!--
By Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman. The 'Dragon Book'. 
From 1985 and they just keep printing it. Considered the standard work on
constructing compilers. 
-->

Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman によるものです。通称 'ド
ラゴンブック'。1985年に出たというのに、えんえんと増刷されています。コ
ンパイラ開発に関しては教科書的存在です。<URL Name="Amazon"
URL="http://www.amazon.com/exec/obidos/ASIN/0201100886/ref=sim_books/002-7737249-1404015">

</descrip>
<p>

<!--
Thomas Niemann wrote a document discussing how to write compilers and
calculators with Lex &amp; YACC. You can find it <URL
URL="http://epaperpress.com/y_man.html" name="here">.
-->

Thomas Niemann は Lex と YACC を使ったコンパイラと電卓の作り方について
ドキュメントを書いており、<URL URL="http://epaperpress.com/y_man.html"
name="ここ">にあります。

<!--
The moderated usenet newsgroup comp.compilers can also be very useful but
please keep in mind that the people there are not a dedicated parser
helpdesk! Before posting, read their interesting <URL name="page"
URL="http://compilers.iecc.com/"> and especially the <URL name="FAQ"
URL="http://compilers.iecc.com/faq.txt">.
-->

comp.compilers というニュースグループも usenet にあり、なかなか利用価
値があります。ですが、参加している人たちは構文解析器の専属ヘルプデスク
要員ではありません! 投稿する前に、彼らの<URL name="ページ"
URL="http://compilers.iecc.com/">は興味深いので見ること、特に質問は
<URL name="FAQ" URL="http://compilers.iecc.com/faq.txt">にちゃんと目を
通した上で投げること。

<!--
Lex - A Lexical Analyzer Generator by M. E. Lesk and E. Schmidt is one of
the original reference papers. It can be found 
<url NAME="here" url="http://www.cs.utexas.edu/users/novak/lexpaper.htm">.
-->

Lex - A Lexical Analyzer Generator by M. E. Lesk and E. Schmidt は筆者
が引用したドキュメントのひとつです。<url NAME="ここ"
url="http://www.cs.utexas.edu/users/novak/lexpaper.htm">で入手できます。

<!--
Yacc: Yet Another Compiler-Compiler by Stephen C. Johnson is one of the
original reference papers for YACC. It can be found
<url NAME="here" url="http://www.cs.utexas.edu/users/novak/yaccpaper.htm">.
It contains useful hints on style.
-->

Yacc: Yet Another Compiler-Compiler by Stephen C. Johnson は筆者が
YACC について引用したドキュメントの一つです。
<url NAME="ここ"
url="http://www.cs.utexas.edu/users/novak/yaccpaper.htm">で入手できま
す。スタイルについてのヒントが載っています。

<sect>
<!--
Acknowledgements &amp; Thanks
-->

謝辞

<p>
<itemize>
<item>Pete Jinks &lt;pjj@cs.man.ac.uk&gt;
<item>Chris Lattner &lt;sabre@nondot.org&gt;
<item>John W. Millaway &lt;johnmillaway@yahoo.com&gt;
<item>Martin Neitzel &lt;neitzel@gaertner.de&gt;
<item>Esmond Pitt &lt;esmond.pitt@bigpond.com&gt;
<item>Eric S. Raymond 
<item>Bob Schmertz &lt;schmertz@wam.umd.edu&gt;
<item>Adam Sulmicki &lt;adam@cfar.umd.edu&gt;
<item>Markus Triska &lt;triska@gmx.at&gt;
<item>Erik Verbruggen &lt;erik@road-warrior.cs.kun.nl&gt;
<item>Gary V. Vaughan &lt;gary@gnu.org&gt; (read his awesome <url NAME="Autobook"
URL="http://sources.redhat.com/autobook">)
<item><url NAME="Ivo van der Wijk" url="http://vanderwijk.info"> (
<url NAME="Amaze Internet" url="http://www.amaze.nl">)
</itemize>

訳注: 翻訳にあたっては、山下義之さん、小林雅典さんに有益なコメントをい
ただきました。ありがとうございました。



</article>

