$(file sequence) : File Sequence
sequence : Sequence
$(dir sequence) : Dir Sequence
sequence : Sequence
file と dir 関数はomakeが動く場所に依存しない、ファイルとディレクトリの位置を定義します。omakeでは、ターゲットをビルドするコマンドはターゲット上のディレクトリにて実行されます。プロジェクト中には多くのディレクトリが存在するため、omakeではあるディレクトリ上のファイルを確実に指定する方法が存在します。これにより、たとえ別のディレクトリ上に移動したとしても、明示的にパスを修正せずに特定のファイルを指定することができます。 file , dir 関数は以下のように用いることで、ディレクトリやファイルのパスが関連付けられます。
例えば、カレントディレクトリ中でファイル foo を示す変数を作ったとしましょう。
FOO = $(file foo)
.SUBDIRS: bar
FOO 変数が bar サブディレクトリ中で展開された場合、これは ../foo と展開されます。
これらのコマンドはトップレベルのディレクトリを確実に指定するために、トップレベルのOMakefileにてしばしば用いられます。よって、ビルドコマンドはこれらのディレクトリを、まるで絶対パスで表しているのように扱うことができます。
ROOT = $(dir .)
LIB = $(dir lib)
BIN = $(dir bin)
これらの変数はいったん定義されたらサブディレクトリ中でもビルドコマンドに使うことができるので、下の $(BIN) はコマンドが実行されたディレクトリに関連付けられた bin ディレクトリで展開されます。
install: hello
cp hello $(BIN)
$(tmpfile prefix) : File
$(tmpfile prefix, suffix) : File
prefix : String
suffix : String
tmpfile 関数は一時的なディレクトリ中にある、一時的な空のファイル名を返します。
$(in dir, exp) : String Array
dir : Dir
exp : expression
in 関数は dir や file 関数と密接に関係しています。ディレクトリとファイル名を指定することで、ディレクトリ上からのファイルの位置を返します。例えば、ファイルをインストールするためによく使われる方法の一つとしてシンボリックリンクを定義することで、その値は特定のディレクトリに関連付けられているものとします。
以下のコマンドでは $(LIB) ディレクトリ中でリンクを生成しています。
FOO = $(file foo)
install:
ln -s $(in $(LIB), $(FOO)) $(LIB)/foo
ノート
in 関数は Node ( File と Dir )が与えられた場合のみに評価を行います。
$(basename files) : String Sequence
files : String Sequence
basename 関数は引数に指定されたファイルのリストから元のファイル名のみを返します。任意のディレクトリパスは除去されます。
例えば、式 $(basename dir1/dir2/a.out /etc/modules.conf /foo.ml) は a.out modules.conf foo.ml と評価されます。
$(dirname files) : String Sequence
files : String Sequence
dirname 関数は引数に指定されたファイルのリストからディレクトリ名を返します。任意のファイル名は除去されます。ディレクトリ部分が指定されていない場合は、”.”が変えされます。
例えば、式 $(dirname dir1\dir2\a.out /etc/modules.conf /foo.ml bar.ml) は dir1/dir2 /etc / . と評価されます。
ノート
この関数は dirof 関数と異なります。 dirname 関数は単純に文字列のシーケンスを解析して返すのに対し、 dirof は File オブジェクトを解析する関数です。
$(rootname files) : String Sequence
files : String Sequence
rootname 関数は引数に指定されたファイルのリストから基底の名前を返します。ここでの『基底の名前』とは拡張子が除去されたファイル名のことです。
例えば、式 $(rootname dir1/dir2/a.out /etc/a.b.c /foo.ml) は dir1/dir2/a /etc/a.b /foo と評価されます。
$(dirof files) : Dir Sequence
files : File Sequence
dirof 関数は引数に指定されたファイルのリストからディレクトリを返します。
例えば、式 $(dirof dir/dir2/a.out /etc/modules.conf /foo.ml) は dir1/dir2 /etc / と評価されます。
$(fullname files) : String Sequence
files : File Sequence
fullname 関数は指定した各々のファイルやディレクトリの、プロジェクトルートを元にしたパスを返します。
ノート
訳注:このような動きをします。
% a = foo/bar
- : "foo/bar" : Sequence
% b = $(fullname $a)
- : <data "/the-root-to-the-project/foo/bar"> : String
$(absname files) : String Sequence
files : File Sequence
absname 関数は指定した各々のファイルやディレクトリの絶対パスを返します。
$(homename files) : String Sequence
files : File Sequence
homename 関数は可能であればチルダ ~ を用いてパス名を返します。展開できない形のパスは遅延的に計算されます。具体的にいうと、 homename 関数は通常、始めてチルダ型のパスとして展開できるようになるまでは、絶対パスとして評価します。
$(suffix files) : String Sequence
files : StringSequence
suffix 関数はファイルのリストから拡張子を返します。もし拡張子が存在しなかった場合、空の文字列が返されます。
例えば、式 $(suffix dir1/dir2/a.out /etc/a /foo.ml) は .out .ml と評価されます。
$(which files) : File Sequence
files : String Sequence
which 関数は現在のコマンド検索パスから実行可能なものを検索し、引数に指定されたコマンドのファイルパスを返します。コマンドが見つからない場合にはエラーが発生します。
where 関数は which 関数と似ていますが、この関数は与えられた実行コマンドのすべての位置をリストとして返します。この場合ですと echo コマンドは Shell オブジェクトによって内的に扱われるので、出力先の最初の文字列ではビルドイン関数として扱われていることを表しています。
% where echo
echo is a Shell object method (a built-in function)
/bin/echo
$(exists-in-path files) : String
files : String Sequence
exists-in-path 関数は引数に指定されたすべてのコマンドが、現在の検索パス上に存在しているかどうか試します。
$(digest files) : String Array
file : File Array
raises RuntimeException
$(digest-optional files) : String Array
file : File Array
digest と digest-optional 関数はファイルのMD5を計算します。 digest 関数はファイルが存在しない場合には例外を送出します。一方で、 digest-optional はこの様な場合 false を返します。また、MD5はキャッシュされます。
$(find-in-path path, files) : File Array
path : Dir Array
files : String Array
raises RuntimeException
$(find-in-path-optional path, files) : File Array
file-in-path 関数は指定されたパスから指定されたファイルを検索します。これらの関数はファイル名が一致した場合のみが処理対称になります(訳注: 一部ではない)。 find-in-path 関数はファイルが見つからない場合には例外を送出します。一方で、 find-in-path-optional 関数はこの様な場合、例外を送出せずに結果から取り除かれます。
$(digest-in-path path, files) : String/File Array
path : Dir Array
files : String Array
raises RuntimeException
$(digest-in-path-optional path, files) : String/File Array
diget-in-path 関数は指定されたパスからファイルを検索し、各々のファイルのファイルパスとMD5を返します。これらの関数はファイル名が一致した場合のみが処理対称になります。 digest-in-path 関数はファイルが見つからない場合には例外を送出します。一方で、 digest-in-path-optional 関数はこの様な場合、例外を送出せずに結果から取り除かれます。
$(file-exists files) : String
$(target-exists files) : String
$(target-is-proper files) : String
files : File Sequence
file-exists 関数はリストされているファイルが存在しているかどうか調べます。 target-exists 関数は file-exists と似ていますが、この関数はファイルが存在するか、現在のプロジェクトでターゲットとなっているような場合に true を返します。 target-is-proper 関数は指定されたファイルが現在のプロジェクトで生成できる場合のみ true を返します。
$(stat-reset files) : String
files : File Sequence
OMakeでは Stat によるキャッシュを行っています。 stat-reset 関数は stat から指定されたファイルの情報をリセットし、次これらの情報が要求された場合には stat 情報が強制的に再計算されます。
$(filter-exists files) : File Sequence
$(filter-targets files) : File Sequence
$(filter-proper-targets) : File Sequence
files : File Sequence
filter-exists , filter-targets , filter-proper-targets 関数は指定されたファイルのリストをフィルタリングして、特定のファイルのみを返します。
プロジェクトによって生成されたファイルを消去する distclean ルールを作るような場合に、一つの簡単な方法が存在します。それは、現在のプロジェクトでビルドすることのできるすべてのファイルを消去することです。
警告
この方法を何も考えずに実行するのではなく、慎重に考えてください。このルールはプロジェクトで作られるであろう すべてのファイル を消去してしまいます。言いかえると、この方法は消去されたファイルのリビルドが成功するかどうかについては、まったく考慮していません。また、この方法では現在のプロジェクトの外にあるファイルは消去されません。
.PHONY: distclean
distclean:
rm $(filter-proper-targets $(ls R, .))
もしあなたがCVSを用いているのであれば、CVSに知らせずにすべてのファイルを消去する distclean ルールを作るのではなく、OMakeによって作られた cvs_realclean プログラムを作りたいと思うことでしょう。例えば、もしあなたが既によく使われている clean ターゲットを作っていたのなら、そしてあなたが distclean ルールをデフォルトでインタラクティブなものにしたいのであれば、以下のように記述することができます。
if $(not $(defined FORCE_REALCLEAN))
FORCE_REALCLEAN = false
export
distclean: clean
cvs_realclean $(if $(FORCE_REALCLEAN), -f) -i .omakedb -i .omakedb.lock
あなたは -i オプションを用いることで、いつでも保持していたいより多くのファイル(設定ファイルなど)を追加することができます。
同様に、Subversionを使っていた場合、OMakeでは build/svn_realclean.om スクリプトを用いて以下のように記述できます。
if $(not $(defined FORCE_REALCLEAN))
FORCE_REALCLEAN = false
export
open build/svn_realclean
distclean: clean
svn_realclean $(if $(FORCE_REALCLEAN), -f) -i .omakedb -i .omakedb.lock
中間ファイルを除去する別の方法についての詳細は、 dependencies-proper 関数を参照してください。
$(find-targets-in-path path files) : File Array
$(find-targets-in-path-optional path, files) : File Array
path : Dir Array
files : File Sequence
find-target-in-path 関数はパス上のターゲットを検索します。指定された各々の file はディレクトリ dir を順番に検索していき、ターゲット dir/file が存在していた場合はファイル dir/file が返されます。
例えば、あなたはCのプロジェクトをビルドしようとしており、そのプロジェクトはサブディレクトリ src/ を含んでおり、その中には fee.c と foo.c が含まれているものとしましょう。そのような場合、以下の式はたとえそのファイルが存在していなくても、 src/fee.o src/foo.o と評価されます。
$(find-targets-in-path lib src, fee.o foo.o)
# このように評価されます。
src/fee.o src/foo.o
find-targets-in-path 関数はファイルが見つからない場合には例外を送出します。一方で、 find-targets-in-path-optional 関数はこの様な場合、例外を送出せずに結果から取り除かれます。
$(find-targets-in-path-optional lib src, fee.o foo.o fum.o)
# このように評価されます。
src/fee.o src/foo.o
find-ocaml-targets-in-path-optional 関数は find-targets-in-path-optional と似ていますが、この関数はパス上のすべての成分と名前を検索し、最初に小文字のバージョンがビルド可能であるか調べた後で、大文字のバージョンがビルド可能であるか調べる、OCamlスタイルの検索が使われます。
$(file-sort order, files) : File Sequence
order : String
files : File Sequence
file-sort 関数はソートルールの集合を用いてビルドのソート順を指定することで、ファイル名のリストをソートします。ソートルールは .ORDER ターゲットを用いて宣言できます。 .BUILDORDER は通常のソート順が定義されています。
$(file-sort <order>, <files>)
例えば、以下のようなルールの集合を考えてみましょう。
a: b c
b: d
c: d
.DEFAULT: a b c d
echo $(file-sort .BUILDORDER, a b c d)
このような場合、 file-sort 関数の結果は d b c a となります。これは依存関係が生成した 後で ターゲットがソートされることを表しています。この関数は依存関係がリンクされてあるファイルをソートする際(依存関係が問題となってくる言語を扱う場合)、頻繁に用いられます。
この関数は3つの重要な制約があります。
ソートルールを使用することで、 file-sort 関数にさらなる制限を加えることができます。ソートルールは2つの手順を用いて宣言します。まず、ターゲットは .ORDER ターゲットに加えなければなりません。次に、ソートルールの集合が与えられていなければなりません。ソートルールには制限(pattern constraint)を定義します。
.ORDER: .MYORDER
.MYORDER: %.foo: %.bar
.MYORDER: %.bar: %.baz
.DEFAULT: a.foo b.bar c.baz d.baz
echo $(sort .MYORDER, a.foo b.bar c.baz d.baz)
この例では、 .MYORDER ソートルールは、拡張子 .foo の任意のファイルは拡張子 .bar の任意のファイルの後に置く必要があり、さらに拡張子 .bar の任意のファイルは拡張子 .baz の任意のファイルの後に置く必要があることを指定しています。
この例では、ソート結果は d.baz c.baz b.bar a.foo となります。
file-check-sort(files)
files : File Sequence
raises RuntimeException
file-check-sort 関数はファイルのリストがソート順になっているかどうか調べます。もしそうならば、リストは変更されずに返されます。そうでない場合は、この関数は例外を送出します。
$(file-check-sort <order>, <files>)
OMakeのコマンドは実行される前に『glob展開』が行われます。これは、ファイル名にはディレクトリやファイル名のシーケンスに展開された パターン を含めることができることを意味しています。文法は標準的なbash(1), csh(1)や以下のルールに従っています。
以下、ディレクトリ /dir にはファイル a , -a , a.b , b.c が含まれているものとします。
[...] : 大括弧の中には文字の集合や、ASCII文字の範囲を指定します。パターンには独立な文字 c や文字の範囲 c1-c2 を含めます。パターンのマッチには任意の文字や任意の範囲を指定することができます。 ^ をつけることで与えられたパターンを反転(指定した文字を含んでいないとマッチする)できます。また、パターンの中に - を含めたい場合、パターンの最初の文字に - と指定しなければなりません。
パターン |
展開 |
|---|---|
/dir/[a-b]* |
/dir/a /dir/a.b /dir/b.c |
dir/[-a-b]* |
/dir/a /dir/-a /dir/a.b /dir/b.c |
/dir/[-a]* |
/dir/a /dir/-a /dir/a.b |
{s1,...,sN} : 中括弧の中にはコンマによって分割された文字列のシーケンスを指定します。N個の文字列が与えられていた場合、結果はN個のパターンのコピーが生成され、各々の文字列はsiとなります。
パターン |
展開 |
|---|---|
a{b,c,d} |
ab ac ad |
a{b{c,d},e} |
abc abd ae |
a{?{[A-Z],d},*} |
a?[A-Z] a?d a* |
チルダ(~)はホームディレクトリを指定する際に用いられます。この値はあなたのシステムに依存して展開されます。
パターン |
展開 |
|---|---|
~jyh |
/home/jyh |
~bob/*.c |
c:\Documents and Settings\users\bob |
\ 文字はパス名のセパレータとしても、文字をエスケープするのにも使われます。もし特殊blob文字の前に用いられていた場合、 \ は次の文字を一種の特殊でない文字に変形します。さもなければ、 \ はパス名のセパレータとして解釈されます。
パターン |
展開 |
|---|---|
~jyh/\* |
~jyh/* (* は文字通り扱われる) |
/dir/\[a-z? |
/dir/[a-z? ( [ は文字通り、 ? はパターンとして扱われる) |
c:\Program Files\[A-z] |
c:\Program Files[A-z]* |
ノート
最後の \ 文字に関するケースは非常に曖昧です。 \ はパス名のセパレータとして扱うべきで、 [ をエスケープするために用いるのではありません。もしあなたがWin32上でこのような解釈を避けたいとするならば、たとえWin32のパス名であっても / を用いるべきです( / は \ に変換されて出力されます)。
パターン |
展開 |
|---|---|
c:/Program Files/[A-z]* |
c:\Program Files\WindowsUpdate ... |
$(glob strings) : Node Array
strings : String Sequence
$(glob options, strings) : Node Array
options : String
strings : String Sequence
glob 関数はglob展開を行います。
. と .. エントリは常に無視されます。
オプションは以下です。
b
csh(1)スタイルの大括弧展開を行いません。
e
\ 文字を特殊文字にエスケープしません。
n
展開が失敗した場合、無視する代わりに展開を文字通り返します。
i
展開が失敗した場合、何も行いません。
.
.から始まるファイルにマッチする、ワイルドカードパターンを許可します。
A
.から始まるファイルを含んだ、すべてのファイルを返します。
F
通常のファイルのみ(ディレクトリでない任意のファイル)にマッチします。
D
ディレクトリファイルのみにマッチします。
C
cvs(1)ルールに関するファイルを無視します。
P
適切なサブディレクトリのみを含みます。
加えて、以下の変数が glob の動作に影響を与えるように定義されています。
GLOB_OPTIONS
デフォルトのオプションを定義している文字列
GLOB_IGNORE
glob が無視すべき、ファイル名のシェルパターンのリスト
GLOB_ALLOW
シェルパターンのリスト。ファイルが GLOB_ALLOW のパターンにマッチしなかった場合、そのファイルは無視されます。
また、返されるファイルは名前順でソートされます。
$(ls files) : Node Array
files : String Sequence
$(ls options, files) : Node Array
files : String Sequence
ls 関数はディレクトリからファイル名を返します。
. と .. エントリは常に無視されます。パターンにはシェルライクなパターンを指定することで、 ls 関数はglob展開を行います。
オプションは glob 関数のオプションをすべて含んでいるほかに、以下のオプションが含まれています。
GLOB_ALLOW と GLOB_IGNORE 変数はglob検索の動作を制御するために定義されています。また、返り値は名前によってソートされます。
$(subdirs dirs) : Dir Array
dirs : String Sequence
$(subdirs options, dirs) : Dir Array
options : String
dirs : String Sequence
subdirs 関数はディレクトリのリストに存在している、すべてのサブディレクトリを再帰的に返します。
とりうることのできるオプションは以下に定義されています。
mkdir(mode, node...)
mode : Int
node : Node
raises RuntimeException
mkdir(node...)
node : Node
raises RuntimeException
mkdir 関数はディレクトリかディレクトリの集合を生成します。以下のオプションがサポートされています。
stat や lstat 関数によって返される Stat オブジェクトはファイルシステムノードについての情報を提供します。このオブジェクトは以下のフィールドを含んでいます。
すべてのフィールドがすべてのOS上で意味をもつわけではない点に注意してください。
$(stat node...) : Stat
node : Node or Channel
$(lstat node...) : Stat
node : Node or Channel
raises RuntimeException
stat 関数はファイル情報を返します。もしファイルがシンボリックリンクであった場合は、 stat 関数はリンク先を参照します。一方で、 lstat 関数はリンク自身を参照します。
$(unlink file...)
file : File
#(rm file...)
file : File
$(rmdir dir...)
dir : Dir
raises RuntimeException
unlink と rm 関数はファイルを削除します。 rmdir 関数はディレクトリを削除します。
rm および rmdir 関数は以下のオプションをサポートしています。
rename(old, new)
old : Node
new : Node
mv(nodes... dir)
nodes : Node Sequence
dir : Dir
cp(nodes... dir)
nodes : Node Sequence
dir : Dir
raises RuntimeException
rename 関数はファイルかディレクトリの名前を old から new に変更します。
mv 関数は似ていますが、もし new がディレクトリでかつ存在している場合、シーケンスによって指定されたファイルはディレクトリの中に移動されます。そうでない場合、 mv の動作は rename と全く同じです。 cp 関数は似ていますが、この関数はオリジナルのファイルを消去しません。
mv と cp 関数は以下のオプションをとります。
link(src, dst)
src : Node
dst : Node
raises RuntimeException
link 関数はファイルやディレクトリ src へのハードリンクを dst に生成します。
ハードリンクはNTFSを用いていた場合は、Win32システム上でも正常に動作します。
通常、スーパーユーザだけがディレクトリへのハードリンクを生成できます。
symlink(src, dst)
src : Node
dst : Node
raises RuntimeException
symlink 関数は src ファイルへのシンボリックリンクを dst に生成します。
リンク名はターゲットのディレクトリに合わせて計算されます。例えば、式 $(symlink a/b, c/d) は c/d -> ../a/b というリンクが生成されます。
シンボリックリンクはWin32上ではサポートされていません。もしクロスプラットフォームでリンク/コピーを行いたい場合は ln-or-cp か Shell エイリアスを使用してください。
chmod(mode, dst...)
mode : Int
dst : Node or Channel
chmod(mode dst...)
mode : String
dst : Node Sequence
raises RuntimeException
chmod 関数は対象のパーミッションを変更します。
オプション:
chown(uid, gid, node...)
uid : Int
gid : Int
node : Node or Channel
chown(uid, node...)
uid : Int
node : Node or Channel
raises RuntimeException
chown 関数はファイルのユーザやグループIDを変更します。もし gid が指定されていない場合は、値は変更されません。IDが-1であった場合でも、そのIDは変更されません。
truncate(length, node...)
length : Int
node : Node or Channel
raises RuntimeException
truncate 関数はファイルを与えられた長さに切り詰めます。
$(umask mode) : Int
mode : Int
raises RuntimeException
ファイル生成マスクを設定します。この関数は前回のマスクの値が返されます。この値はスコープ化されていませんので、この変更はグローバルに影響を及ぼします。
vmount(src, dst)
src, dst : Dir
vmount(flags, src, dst)
flags : String
src, dst : Dir
src ディレクトリを dst ディレクトリに『マウント』します。これは仮想的なマウントで、 $(file ...) 関数のふるまいを変更します。 $(file str) が使われた場合、返される値はもしファイルが存在していたら src ディレクトリに関連付けられます。さもなければファイルは現在のディレクトリに関連付けられます。
vmount 関数の主な目的は、分割された設定やアーキテクチャを用いて、複数のビルドを行うことをサポートするためです。
オプションは以下の通りです。
なお、マウント操作はスコープ化されています。
add-project-directories(dirs)
dirs : Dir Array
omakeがプロジェクトの一部とみなしているディレクトリの集合に、ディレクトリを新しく追加します。これは主に、現在のディレクトリがプロジェクトの一部でないとomakeがエラーを出すことを避けるために用いられます。
remove-project-directories(dirs)
dirs : Dir Array
omakeがプロジェクトの一部とみなしているディレクトリの集合から、ディレクトリを削除します。これは主に、特定のディレクトリがコンパイルされる必要がないことが分かっているので、インクルードしているディレクトリから .SUBDIRS を取り消すような場合に用いられます。
test(exp) : Bool
exp : String Sequence
評価式の文法は以下の通りです。
基本となる評価式は以下の通りです。
str は任意の文字列で、 - 文字をつけることができます。
int は整数として解釈できる文字列です。従来の test プログラムのバージョンとは異なり、先頭の文字にはアリティを指定することもできます。接頭辞 0b は数値をバイナリで扱います。同様に、接頭辞 0o は数値を8進数で扱い、接頭辞 0x は数値を16進数で扱います。 int は -l を用いることで数値を文字列として扱うことができます。これによって、数値ではなく文字列の長さが評価されます。
file はファイル名を表す文字列です。
文法は test(1) プログラムと似ています。もしあなたがUnixのシステム上にいるのならば、manを参照すればさらに詳細を説明してくれるでしょう。以下にいくつかのサンプルを挙げておきます。
# 空のファイルを作成
osh> touch foo
# ファイルは空ですか?
osh> test(-e foo)
- : true
osh> test(! -e foo)
- : false
# 別のファイルを作成
osh> touch boo
# 新しく作ったファイルは前よりも新しいですか?
osh> test(boo -nt foo)
- : true
# さらに複雑な式を示します。
# booはfooよりも新しく、さらにfooは空である。
osh> test(\( boo -nt foo \) -a -e foo)
- : true
find(exp) : Node Array
exp : String Sequence
find 関数はディレクトリを再帰的に検索し、 exp の評価が真であるファイルを返します。
引数の exp は以下の例外を除いて、 test 関数と同じ文法を用いています。
exp の文法は test 関数のそれと同一ですが、以下の点が加わっています。
find 関数はすべてのサブディレクトリを再帰的にスキャンします。以下の関数呼び出しは omake のソースディレクトリのルートから走らせています。
osh> find(. -name fo* )
- : <array
/home/jyh/.../omake/mk/.svn/format
/home/jyh/.../omake/RPM/.svn/format
...
/home/jyh/.../omake/osx_resources/installer_files/.svn/format>
別の例では、通常のファイルかシンボリックリンクのファイルのみを並べています。
osh> find(. -name fo* -a \( -f {} -o -L {} \))
- : <array
/home/jyh/.../omake/mk/.svn/format
/home/jyh/.../omake/RPM/.svn/format
...
/home/jyh/.../omake/osx_resources/installer_files/.svn/format>
以下の変数が標準出力先として定義されています。
stdin
stdin : InChannel
標準入力チャネルで、読み込みを担当します。
stdout
stdout : OutChannel
標準出力チャネルで、書き込みを担当します。
stderr
stderr : OutChannel
標準エラーャネルで、書き込みを担当します。
open-in-string 関数は文字列をまるでファイルのように扱い、読み込むためのチャネルを返します。
$(open-in-string s) : Channel
s : String
open-out-string 関数はファイルの代わりに文字列を書き込むチャネルを作成します。文字列は out-contents 関数を用いて取得することができます。
$(open-out-string) : Channel
$(out-contents chan) : String
chan : OutChannel
fopen 関数はファイルを読み書きするために、新しくファイルを開きます。
$(fopen file, mode) : Channel
file : File
mode : String
file は読み書きするファイル名を指定します。 mode は以下の文字を組み合わせた文字列です。
Unixシステム上ではバイナリモードは意味を持たず、テキストモードとバイナリモードは等価に扱われます。
$(read channel, amount) : String
$(input-line channel) : String
channel : InChannel
amount : Int
raises RuntimeException
read 関数は amount バイトを入力チャネルから読み込み、読み込んだデータを返します。 input-line 関数はファイルから一行を読み込み、読み込んだ一行を改行コード抜きで返します。もしファイルの終わりまでたどり着いた場合、両方の関数は例外 RuntimeException を送出します。
$(write channel, buffer, offset, amount) : String
channel : OutChannel
buffer : String
offset : Int
amount : Int
$(write channel, buffer) : String
channel : OutChannel
buffer : String
raises RuntimeException
4つ引数をとる場合、 write 関数は出力チャネル channel に位置 offset から、バイト buffer を書き込みます。なお、上限は amount バイトです。この関数は何バイトが書き込まれたのかというバイト数を返します。
3つ引数をとる場合も同様ですが、 offset は0となります。
2つ引数をとる場合、 offset は0で、かつ amount は buffer の長さになります。
ファイルの終わりまでたどり着いた場合、この関数は例外 RuntimeException を送出します。
$(lseek channel, offset, whence) : Int
channel : Channel
offset : Int
whence : String
raises RuntimeException
lseek 関数はチャネル channel のオフセット位置を whence に基づいて変更します。 whence は以下の通りです。
lseek 関数はファイルの新しいオフセット位置を返します。
$(tell channel...) : Int...
channel : Channel
raises RuntimeException
tell 関数は channel の現在位置を返します。
$(flush channel...)
channel : OutChannel
flush 関数は書き込み用途にファイルが開かれている場合のみに使われます。この関数はファイルにまだ書き込まれていないすべてのデータを消去します。
$(channel-name channel...) : String
channel : Channel
channel-name 関数はチャネルに関係している名前を返します。
$(dup channel) : Channel
channel : Channel
raises RuntimeException
dup 関数は引数に指定されたチャネルと同一のファイルを示している、新しいチャネルを返します。
dup2(channel1, channel2)
channel1 : Channel
channel2 : Channel
raises RuntimeException
dup2 関数は channel2 を channel1 と同一のファイルを示すようにします。
set-nonblock-mode(mode, channel...)
channel : Channel
mode : String
set-nonblock-mode 関数は与えられたチャネルのノンブロッキングフラグを設定します。もしチャネルが入出力中で、この操作が即座に完了しないような場合、 RuntimeException が送出されます。
set-close-on-exec-mode 関数は与えられたチャネルのclose-on-execフラグを設定します。もしclose-on-execフラグが設定されている場合、このチャネルは子プロセスから継承されません。そうでない場合は、このチャネルは子プロセスから継承されます。
$(pipe) : Pipe
raises RuntimeException
pipe 関数は2つのフィールドを持つ Pipe オブジェクトを生成します。 read フィールドは読み込むためのチャネルで、 write フィールドは書き込むためのチャネルです。
$(select rfd..., wfd..., efd..., timeout) : Select
rfd : InChannel
wfd : OutChannel
efd : Channel
timeout : float
raises RuntimeException
select 関数は与えられたチャネルの集合が入出力可能であるか監視します。 rfd には読み込み可能なチャネルのシーケンスを指定します。 wfd には書き込み可能なチャネルのシーケンスを指定します。 efd にはエラー状態を監視するチャネルのシーケンスを指定します。 timeout にはイベントを待つ最大時間を指定します。
正常な戻り値の場合、 select 関数は以下のフィールドを持つ Select オブジェクトを返します。
lockf(channel, command, len)
channel : Channel
command : String
len : Int
raises RuntimeException
lockf 関数は与えられたチャネルのPOSIXロックの範囲を設定します。範囲は現在の位置から len バイトまでです。
command のとりうる値は以下の通りです。
InetAddr オブジェクトはインターネットアドレスを記述しています。このオブジェクトは以下のフィールドを含んでいます。
Host オブジェクトは以下のフィールドを含んでいます。
$(gethostbyname host...) : Host...
host : String
raises RuntimeException
gethostbyname 関数は指定されたホストの Host オブジェクトを返します。 host にはドメイン名かインターネットアドレスを指定します。
Protocol オブジェクトはプロトコルエントリーを表現します。このオブジェクトは以下のフィールドを含んでいます。
$(getprotobyname name...) : Protocol...
name : Int or String
raises RuntimeException
getprotobyname 関数は指定されたプロトコルから Protocol オブジェクトを返します。 name にはプロトコル名かプロトコル番号を指定します。
Service オブジェクトはネットワークサービスを表現します。このオブジェクトは以下のフィールドを含んでいます。
$(getservbyname service...) : Service...
service : String or Int
raises RuntimeException
getservbyname 関数はネットワークサービスの情報を取得します。 service にはサービス名か番号を指定します。
$(socket domain, type, protocol) : Channel
domain : String
type : String
protocol : String
raises RuntimeException
socket 関数は束縛されていないソケットを生成します。
引数のとりうる値は以下の通りです。
domain は以下の値をとります。
type は以下の値をとります。
protocol はプロトコルのデータベースにあるプロトコルを指定した Int か String 型の引数です。
bind(socket, host, port)
socket : InOutChannel
host : String
port : Int
bind(socket, file)
socket : InOutChannel
file : File
raise RuntimeException
bind 関数はソケットをアドレスに束縛します。
3つ引数をとる場合、 bind 関数はインターネットの接続方法について指定し、 host にはホスト名かIPアドレスを、 port にはポート番号を指定します。
2つ引数をとる形は Unix ソケットのために用意されています。 file にはファイル名のアドレスを指定します。
listen(socket, requests)
socket : InOutChannel
requests : Int
raises RuntimeException
listen 関数は requests 個のまだ取得されていないリクエストを取得するように、ソケットを設定します。
$(accept socket) : InOutChannel
socket : InOutChannel
raises RuntimeException
accept 関数はソケットの接続を受け入れます。
connect(socket, addr, port)
socket : InOutChannel
addr : String
port : int
connect(socket, name)
socket : InOutChannel
name : File
raise RuntimeException
connect 関数はソケットを対象のアドレスに接続します。
3つ引数をとる場合、 connect 関数はインターネットの接続方法について指定します。 addr にはリモートホストのインターネットアドレスをドメイン名かIPアドレスの形で指定します。 port にはポート番号を指定します。
2つ引数をとる形はUnixソケットのために用意されています。 name にはソケットのファイル名を指定します。
$(getc) : String
$(getc file) : String
file : InChannel or File
raises RuntimeException
getc 関数はファイルの次の文字を返します。もし引数が指定されなかった場合、 stdin が入力として用いられます。もしファイルの終わりまでたどりついた場合、この関数は false を返します。
$(gets) : String
$(gets channel) : String
channel : InChannel or File
raises RuntimeException
gets 関数はファイルから次の行を返します。この関数はファイルの終わりまでたどり着いていた場合、空の文字列を返します。改行コードは取り除かれます。
$(fgets) : String
$(fgets channel) : String
channel : InChannel or File
raises RuntimeException
fgets 関数は fopen によって読み込みが開かれているファイルから、次の行を返します。この関数はファイルの終わりまでたどり着いていた場合、空の文字列を返します。返される文字列は文字通りのデータ(literal data)として返されます。改行コードは取り除かれません。
print と println 関数を用いて出力を表示します。 println 関数は表示する値に新しく改行コードを加えます。 print 関数は加えません。
fprint(<file>, <string>)
print(<string>)
eprint(<string>)
fprintln(<file>, <string>)
println(<string>)
eprintln(<string>)
fprint 関数は fopen で開かれたファイルに対して出力します。 print 関数は標準出力チャネルに対して出力しますが、 eprint 関数は標準エラーチャネルに対して出力します。
値は printv と printvln 関数を用いて表示できます。 printvln 関数は表示する値に新しく改行コードを加えます。 printv 関数は加えません。
fprintv(<file>, <string>)
printv(<string>)
eprintv(<string>)
fprintvln(<file>, <string>)
printvln(<string>)
eprintvln(<string>)
fprinv 関数は fopen で開かれたファイルに対して出力します。 printv 関数は標準出力チャネルに対して出力しますが、 eprintv 関数は標準エラーチャネルに対して出力します。
多くの高レベルな関数では正規表現を使用しています。正規表現はawk(1)の文法とだいたい似ている文字列から成り立っています。
文字列には以下の文字定数を含めることができます。
正規表現は特殊文字 .\^$[(){}*?+ を使うことができます。
上の文字クラスは文字のシーケンスを絶対的に指定するのに用いられます。これらのシーケンスはあなたの言語環境次第で変更することもできます。
cat(files) : Sequence
files : File or InChannel Sequence
cat 関数は複数のファイルを連結し、文字列として返します。
grep(pattern) : String # stdin から入力され、デフォルトのオプションが用いられる
pattern : String
grep(pattern, files) : String # デフォルトのオプションが用いられる
pattern : String
files : File Sequence
grep(options, pattern, files) : String
options : String
pattern : String
files : File Sequence
grep 関数はファイルの集合から正規表現 pattern に適合しているものを検索し、マッチした行を表示します。これはgrep(1)の高度に簡素化されたバージョンです。
オプションは以下の通りです。
pattern は正規表現です。
もし成功した ( grep がマッチした行を見つけた)場合、この関数は true を返します。そうでない場合は false を返します。
scan(input-files)
case string1
body1
case string2
body2
...
default
bodyd
scan 関数はコマンドライン上からの入力機能を提供します。この関数はファイル、あるいはファイル名を引数にとります。もし何も引数が呼ばれなかった場合、 stdin から入力されます。もし引数が指定された場合、各々の引数には InChannel が指定されるか、入力としてファイル名が用いられます。なお、出力は常に stdout です。
scan 関数は入力から一行を読み込み、以下のアルゴリズムに従って処理を行います。
各々の行で、レコードはまずいくつかのフィールドに分割され、それらのフィールドは変数 $1, $2, ... に束縛されます。変数 $0 は行全体として定義されており、 $* はすべてのフィールドの値が定義されている配列です。 $(NF) 変数はフィールドの数が定義されています。
次に case 文が実行されます。もし string_i がトークン $i にマッチした場合、 body_i が評価されます。もし case の内容が export で終わっていたのなら、現在の状態は次の宣言句へ受け継がれます。そうでない場合、この値は捨てられます。
例えば、以下の scan 関数は単純なコマンドプロセッサのように振る舞います。
calc() =
i = 0
scan(script.in)
case print
println($i)
case inc
i = $(add $i, 1)
export
case dec
i = $(sub $i, 1)
export
case addconst
i = $(add $i, $2)
export
default
eprintln($"Unknown command: $1")
scan 関数はまたいくつかのオプションをサポートしています。
scan(options, files)
...
ノート
もしあなたが出力をファイルにリダイレクトしたい場合、最も簡単な方法は stdout 変数を再定義することです。 stdout 変数は他の変数と同様スコープ化されているので、この再定義は calc 関数の外にある stdout には影響を及ぼしていません。
calc() =
stdout = $(fopen script.out, w)
scan(script.in)
...
close(stdout)
awk(input-files)
case pattern1:
body1
case pattern2:
body2
...
default:
bodyd
あるいは
awk(options, input-files)
case pattern1:
body1
case pattern2:
body2
...
default:
bodyd
awk 関数はawk(1)と似た入力機能を提供します。が、この関数は制限されています。引数 input-files には値のシーケンスを指定することで、各々の値には InChannel が指定されるか、入力としてファイル名が用いられます。もしオプションとファイルの引数が何も指定されなかったら、入力は stdin が用いられます。なお、出力は常に stdout です。
変数 RS と FS にはレコードとフィールドを分割するセパレータが正規表現の形で定義されています。なお、デフォルトの RS の値は正規表現 \r|\n|\r\n で、 FS は [ \t]+ です。
awk 関数は入力から一つのレコードを読み込み、以下のアルゴリズムに従って処理を行います。
各々の行で、レコードはまずフィールドセパレータ FS を用いていくつかのフィールドに分割され、それらのフィールドは変数 $1, $2, ... に束縛されます。変数 $0 は行全体として定義されており、 $* はすべてのフィールドの値が定義されている配列です。変数 $(NF) はフィールドの数が定義されています。
次に、 case が順番どおりに評価されていきます。各々の case において、もし正規表現 pattern_i がレコード $0 にマッチしていた場合は、 body_i が評価されます。もし body_i が export で終わっていたのなら、現在の状態は次の宣言句へ受け継がれます。そうでない場合、この値は捨てられます。もし正規表現が \(r\) を含んでいたのなら、フィールド $1, $2, ... はこれらの表現で書き換えられます。
例えば、以下のコードはテキストが二つのデリミタ \begin{<name>} と \end{<name>} の間にあり、さらに filter 関数の引数として渡された配列の中に <name> が入っているときだけ、その間のテキストを出力しています。
filter(names) =
print = false
awk(Awk.in)
case $"^\\end\{\([:alpha:]+\)\}"
if $(mem $1, $(names))
print = false
export
export
default
if $(print)
println($0)
case $"^\\begin\{\([:alpha:]+\)\}"
print = $(mem $1, $(names))
export
ノート
もしあなたが出力をファイルにリダイレクトしたい場合、最も簡単な方法は stdout 変数を再定義することです。 stdout 変数は他の変数と同様スコープ化されているので、この再定義は filter 関数の外にある stdout には影響を及ぼしていません。
filter(names) =
stdout = $(fopen file.out, w)
awk(Awk.in)
...
close(stdout)
オプション :
break 関数はループを停止する際に用いられます。これを用いると awk 関数は即座に中断します。
fsubst(files)
case pattern1 [options]
body1
case pattern2 [options]
body2
...
default
bodyd
fsubst 関数は sed(1) のような置換機能を提供します。 awk と似ていて、もし fsubst が何の引数も指定されずに呼び出された場合、入力は stdin が用いられます。もし引数が与えられていた場合、各々の引数は InChannnel が指定されるか、入力としてファイル名が用いられます。
RS 変数はレコードのセパレータを指定する正規表現が定義されており、 RS のデフォルトの値は \r|\n|\r\n です。
fsubst 関数は1回につき1つのレコードを読み込みます。
各々のレコードで、 case 文は順番どおりに評価されます。各々の case ではマッチした pattern を、定義された文字列に置換する機構について定義しています。
現在のところ、omakeでは g オプションだけがサポートされています。指定した場合、各々の宣言句は全体の置換を行い、すべての pattern のインスタンスによって置換が行われます。そうでない場合、置換は1回だけ行われます。
出力は stdout 変数を再定義することによってリダイレクトできます。
例えば、以下のプログラムは word に適合した文字列すべてを大文字化し、置換します。
section
stdout = $(fopen Subst.out, w)
fsubst(Subst.in)
case $"\<\([[:alnum:]]+\)\." g
value $(capitalize $1).
close(stdout)
lex(files)
case pattern1
body1
case pattern2
body2
...
default
bodyd
lex 関数はシンプルな文法解析器を提供します。入力はファイルやチャネルのシーケンスです。 case には正規表現を指定します。この関数は入力を読み込むたび、 最も長い接頭辞 にマッチした正規表現を選択し、その内容を評価します。
同じ長さで2つの case 文がマッチしてしまった場合、 後ろの case 文が実行されます。 default 文は正規表現 . にマッチするので、パターンリストの最初に設置するのが恐らく望ましいでしょう。
もし case の内容が export で終わっていたのなら、現在の状態は次のループへ受け継がれます。
例えば、以下のプログラムは入力されたファイルからすべての英数字を集めます。
collect-words($(files)) =
words[] =
lex($(files))
default
# empty
case $"[[:alnum:]]+" g
words[] += $0
export
default 文が存在する場合、この文は任意の1つの文字のみにマッチします。また、もし入力がどの正規表現にもマッチしなかった場合、この関数はエラーとなります。
break 関数はループを停止する際に用いられます。
lex-search(files)
case pattern1
body1
case pattern2
body2
...
default
bodyd
lex-search 関数は lex 関数と似ていますが、この関数はどの正規表現にもマッチしなかった入力をスキップします。 default 文を含んでいた場合、 default はすべてのスキップしたテキストにマッチします。
例えば、以下のプログラムは入力されたファイルからすべての英数字文字を集め、含まれていない他のテキストはスキップします。
collect-words($(files)) =
words[] =
lex-search($(files))
default
eprintln(Skipped $0)
case $"[[:alnum:]]+" g
words[] += $0
export
default 文が存在する場合、この文は任意の1つの文字のみにマッチします。また、もし入力がどの正規表現にもマッチしなかった場合、この関数はエラーとなります。
break 関数はループを停止する際に用いられます。
Lexer オブジェクトは容易に字句解析を行えるようにするオブジェクトで、 lex(1) や flex(1) プログラムと似ています。
omakeでは、字句の解析は Lexer クラスを継承することによって動的に構成することができます。字句解析器(以後レキサと呼ぶ)の定義はメソッドを呼び出すことで指示文(directive)を指定しているものの集合と、ルールとして宣言句(clause)を指定しているものの集合によって成り立っています。
例えば、以下のシンプルなデスクトップ電卓の演算の字句解析を行う、レキサの定義について考えてみましょう。
lexer1. =
extends $(Lexer)
other: .
eprintln(Illegal character: $* )
lex()
white: $"[[:space:]]+"
lex()
op: $"[-+*/()]"
switch $*
case +
Token.unit($(loc), plus)
case -
Token.unit($(loc), minus)
case *
Token.unit($(loc), mul)
case /
Token.unit($(loc), div)
case $"("
Token.unit($(loc), lparen)
case $")"
Token.unit($(loc), rparen)
number: $"[[:digit:]]+"
Token.pair($(loc), exp, $(int $* ))
eof: $"\'"
Token.unit($(loc), eof)
このプログラムは Lexer オブジェクトから字句解析の環境を定義している lexer1 を継承しています。
残りの定義では宣言句の集合の定義を行っています。コロン(:)の前にはメソッド名を指定し、コロンの後には正規表現を指定します。この場合は内容も指定しています。内容はなくても構いません。指定されなかった場合、レキサの定義で既に存在している、与えられたメソッド名が用いられます。
警告
最も長い 接頭辞にマッチした宣言句が選択されます。もし2つの宣言句が同じ長さの場合、 後ろの 宣言句が選択されます。これはほとんどの標準的なレキサとな異なっていますが、拡張性から見ればこの仕様は大きな意味を持ちます。
最初の宣言句は他の宣言句にマッチしなかった任意の入力文字列がマッチします。この場合、未知の文字のエラーメッセージが出力されます。この宣言句は他の宣言句にマッチしなかった場合のみ選択されることに注意してください。
2番目の宣言句ではホワイトスペースを無視する役割を持っています。ホワイトスペースが見つかった場合、これを無視し、再帰的にレキサを呼び出します。
3番目の宣言句では演算子の役割を持っています。ここでは Token オブジェクトを利用しています。なお、この Token オブジェクトは3つのフィールド(ソース位置を表現している loc , name , value)を定義しています。
レキサは各々のメソッドの body 部で、現在の語彙素(lexeme)の位置を表す loc 変数が定義されているので、私たちはトークンを生成するためにこの値を用いています。
Token.unit($(loc), name) メソッドは与えられた名前とデフォルトの値を用いて新しい Token オブジェクトを構成します。
number 宣言句は正の整数の定数にマッチします。 Token.pair($(loc), name, value) は与えられた名前と値でトークンを構成します。
Lexer オブジェクトは InChannel オブジェクトを操作します。 lexer1.lex-channel(channel) メソッドは与えられたチャネルから次のトークンを読み込みます。
字句解析においては、最も長くマッチした宣言句が選択されます。これは、最も長い入力文字のシーケンスにマッチした宣言句が評価対象になるということです。もしどの宣言句にもマッチしなかった場合、レキサは RuntimeException を送出します。もし1つ以上の宣言句が同じ量の入力にマッチした場合、最初の1つが評価に用いられます。
それでは前回のレキサのサンプルを、コメントを無視するように拡張してみましょう。ここで、コメントを (* から *) で終わる任意のテキストとして定義します。なお、コメントはネスト化されているものとします。
これを実現する一つの簡単な方法としては、コメントをスキップする別のレキサを定義することが挙げられます。
lex-comment. =
extends $(Lexer)
level = 0
other: .
lex()
term: $"[*][)]"
if $(not $(eq $(level), 0))
level = $(sub $(level), 1)
lex()
next: $"[(][*]"
level = $(add $(level), 1)
lex()
eof: $"\'"
eprintln(Unterminated comment)
このレキサには、ネストレベルを記録し続けている lebel フィールドを含んでいます。 (* に遭遇すると、この変数はレベルを1増やし、 *) が来たら、0でない場合はレベルを1減らし、続けます。
次に、前回のレキサを、コメントをスキップするような形に修正してみましょう。これはちょうど前に作った lexer1 オブジェクトを拡張することで実現できます。
lexer1. +=
comment: $"[(][*]"
lex-comment.lex-channel($(channel))
lex()
comment 宣言句の内容にはコメントに遭遇した場合、 lex-comment レキサを呼び出し、このレキサが返されたときに解析し続けることを指定しています。
宣言句の内容はまた指示文のエクスポートで終了します。この場合、レキサオブジェクト自身がトークンを返すものとして使われます。もしレキサオブジェクトの上で Parser オブジェクトを使うのであれば、レキサは loc , name , value フィールドを、各々の export 宣言句の中で定義すべきです。毎回 Parser オブジェクトはレキサを呼び出し、さらに前回のレキサを起動することで返されるレキサを呼び出します。
Parser オブジェクトは『文脈自由な文法(context-free grammars)』をベースとした、文法解析機能を提供しています。
Parser オブジェクトは指示文のシーケンスとして指定されます。また、 Parser オブジェクトはメソッドの呼び出し、生成、ルールの指定も担当しています。
例えば、前回の Lexer のサンプルを使って、デスクトップ計算機を作ってみましょう。
parser1. =
extends $(Parser)
#
# 主に使うレキサを定義
#
lexer = $(lexer1)
#
# 昇順に優先順位を定義
#
left(plus minus)
left(mul div)
right(uminus)
#
# プログラム
#
start(prog)
prog: exp eof
return $1
#
# 単純な算術式定義
#
exp: minus exp :prec: uminus
neg($2)
exp: exp plus exp
add($1, $3)
exp: exp minus exp
sub($1, $3)
exp: exp mul exp
mul($1, $3)
exp: exp div exp
div($1, $3)
exp: lparen exp rparen
return $2
パーサは Parser クラスの式として定義されています。パーサオブジェクトは lexer フィールドを持たなければなりません。 lexer は Lexer オブジェクトでなければならないというわけではありませんが、トークンオブジェクトを返す lexer.lex() メソッドと name , value フィールドを提供していなければなりません。例えば、今回私たちは前回の項で定義した lexer1 オブジェクトを使用しました。
次のステップでは演算子記号の優先順位を定義します。優先順位は left , right , nonassoc メソッドの順に上がっていきます( left が一番下で nonassoc が一番上)。
文法(grammar)は最低でも一つの開始記号を持たなければなりません。これは start メソッドで宣言できます。
次に、文法の中の生成部(productions)はルールに従って並べられます。生成部の名前はコロンの前に指定し、変数のシーケンスはコロンの後に指定します。内容部には、生成部が入力の一部として解釈された場合における、意味論的な行動(semantic action)を指定します。
今回の例では、デスクトップの計算機によって解析された算術式を生成しています。今回の場合、『意味論的な行動』は数値計算としてふるまいます。変数 $1, $2, ... は生成部の右から順に、各々の変数に関連付けられた値として扱われます。
パーサは $(parser1.parse-channel start, channel) や $(parser1.parse-file start, file) で呼び出されます。 start 引数には開始記号を指定し、 channel あるいは file にはパーサへの入力を指定します。
パーサの生成器はLALR(1)テーブルをベースにした、『先読み後出しのオートメーション(pushdown automation)』を生成します。通常、文法が曖昧である場合には、このオートメーションは『移動してから減らすのか』あるいは『減らしてからさらに減らすのか』で衝突することになります。これらの衝突はオートメーションが生成された時点で、標準出力に表示されます。
通常は、オートメーションはパーサが始めて使われることになるまで構築されません。
build(debug) メソッドはオートメーションの構築を強制的に行います。 build(debug) メソッドを呼び出すことによって、各々のパーサが要求されなくなるまで完全に構築させるというのは賢い方法です。 debug 変数が設定されている場合、このメソッドはパーサテーブルの任意の衝突をそれぞれ出力します。
loc 変数は行動部(action bodies)の内部で定義されます。また、生成部の右側にある、すべてのトークンの入力範囲を表現します。
パーサはまた継承することで拡張できます。例えば、文法を拡張することでシフト演算 << と >> を理解できるようにしてみましょう。
初めに、私たちはレキサを拡張することで、これらのトークンを理解できるようにします。今回、私たちは += 演算子を使う代わりに、既存の lexer1 を完全なものにすることを選びました。
lexer2. =
extends $(lexer1)
lsl: $"<<"
Token.unit($(loc), lsl)
asr: $">>"
Token.unit($(loc), asr)
次に、私たちはこれらの新しい演算子を扱うように、既存のパーサを拡張しました。ビット演算子は既存の算術演算子よりも低い優先順位にするつもりです。今回は二つの引数をとる left メソッドを使うことで実現しました。
parser2. =
extends $(parser1)
left(plus, lsl lsr asr)
lexer = $(lexer2)
exp: exp lsl exp
lsl($1, $3)
exp: exp asr exp
asr($1, $3)
今回の場合、私たちは新しいレキサ lexer2 を使用して、さらに新しいシフト演算子の生成部を追加しました。
Passwd オブジェクトはシステムユーザのデータベース上にあるエントリを表現します。このオブジェクトは以下のフィールドを持っています。
すべてのフィールドがすべてのOS上で意味をもつわけではないことに注意してください。
$(getpwnam name...) : Passwd
name : String
$(getpwuid uid...) : Passwd
uid : Int
raises RuntimeException
getpwnam 関数はユーザのログイン名からエントリを探しだします。 getpwuid 関数はユーザID(numerical id, uid)からエントリを探し出します。もしエントリが見つからなかった場合、例外が送出されます。
$(getpwents) : Array
getpwents 関数は Passwd オブジェクトの配列を返します。すべてのユーザは、システムユーザのデータベースによって用意されます。この関数はOSやユーザデータベースの状況に依存し、返される配列は完全でなかったり、空である可能性もある点に注意してください。
Group オブジェクトはシステムのユーザグループに関するデータベースのエントリを表現します。このオブジェクトは以下のフィールドを含んでいます。
すべてのフィールドがすべてのOSで意味を持つわけでは無い点に注意してください。
$(getgrnam name...) : Group
name : String
$(getgrgid gid...) : Group
gid : Int
raises RuntimeException
getgrnam 関数はグループ名からグループエントリを探しだし、 getgrgid 関数はグループID(gid)からエントリを探し出します。何も見つからなかった場合は例外が送出されます。
$(tgetstr id) : String
id : String
tgetstr 関数は指定された id を用いて『端末の能力(terminal capability, termcap)』を調べます。これは、”terminfo”の調査が TERM 環境変数によって与えられることを保証しています。もし与えられた”terminal capability”が定義されていなかった場合、この関数は空の値を返します。
ノート
シェルプロンプト内部の tgetstr によって返された値を使用したい場合、あなたは prompt-invisible 関数を用いてラップする必要があります。
$(xterm-escape-begin) : String
$(xterm-escape-end) : String
xterm-escape-begin と xterm-escape-end 関数はXTermのウィンドウタイトルを設定したい場合に用いることができる、エスケープのシーケンスを返します。この機能が使えない場合、この関数は空の値を返します。
ノート
シェルプロンプト内部の値を用いるようにしたい場合、あなたは $(prompt_invisible_begin)$(xterm-escape-begin) と $(xterm-escape-end)$(prompt_invisible_end) を使う必要があります。
$(xterm-escape s) : Sequence
TERM 環境変数が『XTermのタイトルを設定する機能が利用できる』ことを表していた場合、 $(xterm-escape s) は $(xterm-escape-begin)s$(xterm-escape-end) と等価です。そうでない場合、この関数は空の値を返します。
ノート
シェルプロンプト内部の xterm-escape によって返された値を用いるようにしたい場合、あなたは prompt-invisible 関数を使ってラップする必要があります。
$(prompt-invisible-begin) : String
$(prompt-invisible-end) : String
prompt-invisible-begin と prompt-invisible-end 関数は、シェルプロンプトに『見えない』セクション(様々なエスケープシーケンスのような)を設定するために用いる必要のある、エスケープのシーケンスを返します。
$(prompt-invisible s) : Sequence
prompt-invisible は指定された引数を $(prompt-invisible-begin) と $(prompt-invisible-end) でラップします。シェルプロンプトに『見えない』すべてのセクション(様々なエスケープシーケンスのような)はこの方法でラップしなければなりません。