[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34. 構文テーブル

構文テーブル(syntax table)は, 各文字の構文的なテキスト上の機能を指定します. この情報は, 構文解析関数や複雑な移動を行うコマンドなどが 単語やシンボルなどの構文要素がどこで始まりどこで終るかを調べるために使います. 現在の構文テーブルが, 本章の関数に加えて, 単語単位の移動関数(see section 単語単位の移動), リスト単位の移動関数(see section 式単位の移動)の意味を制御します.


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34.1 構文テーブルの概念

構文テーブルは文字テーブル(see section 文字テーブル)です. cで添字付けられる要素は, コードがcである文字について記述します. 要素の値は, 当該文字の構文上の機能を符号化したリストです.

構文テーブルは, テキスト内を動き回るためにのみ使われ, EmacsのLispリーダはこれを使いません. Emacs LispがLisp式を読むときには, 組み込みの構文規則を使います. (入力構文を再定義する方法を与えるLispシステムもあるが, 単純であるようにEacs Lispではこの機能を省くことにした. )

各バッファには独自のメジャーモードがあり, 各メジャーモードはさまざまな文字の構文クラスを独自に扱います. たとえば, lispモードでは文字‘;’はコメントを始めますが, Cモードでは文を終らせます. このような多様性を扱うために, Emacsは各バッファごとにローカルな構文テーブルを選びます. 典型的には, 各メジャーモードに独自の構文テーブルがあり, そのモードを使っているバッファに当該構文テーブルをインストールします. この構文テーブルを変更すると, 同じモードのバッファだけでなく将来そのモードになったバッファでも 構文を変更してしまいます. 類似したモードでは1つの構文テーブルを共有することがあります. 構文テーブルの設定方法の例については, See section メジャーモードの例.

構文テーブルでは, 標準の構文テーブルから文字のデータを継承し, 一方でその他の文字に独自の指定を行えます. 構文クラスの『継承』とは, 『標準の構文テーブルから当該文字の構文を引き継ぐ』ことです. ある文字に対して標準の構文を変更すると, それを継承するすべての構文テーブルに影響します.

Function: syntax-table-p object

この関数は, objectが構文テーブルならばtを返す.


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34.2 構文記述子

本節では, 文字の構文を指定する構文クラスと構文フラグ, それらを構文記述子(syntax descriptor)としてどのように 表現するかについて述べます. 構文記述子はLisp文字列であり, 望みの構文を指定するためにmodify-syntax-entryに渡します.

構文テーブルは, 各文字の構文クラスを指定します. ある構文テーブルでの文字のクラスと 他の構文テーブルでの当該文字のクラスとのあいだにはなんの関係も必要ありません.

各クラスはニーモニック文字(指定子)で区別します. ニーモニック文字は, クラスを指定する必要があるときにクラス名として働きます. 通常, 指定子の文字は当該クラスによく現れるものです. しかしながら, 指定子としての意味は不変で, その文字の現在の構文とは独立です.

構文記述子は, 構文クラス, (括弧のクラスの場合にのみ使われる) 釣り合う文字, フラグを指定するLisp文字列です. 最初の文字は, 構文クラスを指定する文字(指定子)です. 2番目の文字はその文字に釣り合う文字ですが, 使用しない場合には空白です. そのあとに望みのフラグが続きます. 釣り合う文字やフラグが必要なければ, 文字1つだけで十分です.

たとえば, Cモードにおける文字‘*’の構文記述子は ‘. 23’(句読点, 釣り合う文字なし, コメント開始の2番目の文字, コメント終了の最初の文字)であり, ‘/’は‘. 14’(句読点, 釣り合う文字なし, コメント開始の最初の文字, コメント終了の2番目の文字)です.


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34.2.1 構文クラス一覧

以下の一覧は, 構文クラス, そのクラスを表す文字(指定子), そのクラスの意味, その使用例です.

構文クラス: 白文字(whitespace character)

白文字(‘ ’か‘-’で指定)は, シンボルや単語を互いに区切る. 典型的には, 白文字には他の構文上の意味はなく, 複数個の白文字は1つの白文字と構文的には等価である. ほとんどすべてのメジャーモードでは, 空白, タブ, 改行, ページ送りは白文字である.

構文クラス: 単語構成文字(word constituent)

単語構成文字(‘w’で指定)は普通の英単語の一部分であり, 典型的には, プログラムの変数やコマンド名に使われる. すべての大英文字, 小英文字, 数字文字は, 典型的には単語構成文字である.

構文クラス: シンボル構成文字(symbol constituent)

シンボル構成文字(‘_’で指定)は, 単語構成文字に加えて, 変数やコマンド名に使われる追加の文字である. たとえば, 英単語の一部分ではないがシンボル名に使える特定の文字を指定 するために, Lispモードではシンボル構成文字クラスを使う. このような文字は‘$&*+-_<>’である. 標準のCでは, 単語構成文字でなくてシンボルに使える唯一の文字は 下線(‘_’)である.

構文クラス: 句読点文字(punctuation character)

句読点文字(‘.’で指定)は, 英文の句読点として使われたり, プログラム言語でシンボルを区切るために使われる文字である. emacs-lispモードを含むほとんどのプログラム言語向けモードでは, シンボル構成文字でも単語構成文字でもない少数の文字には別の用途があるため, このクラスの文字はない.

構文クラス: 開き括弧文字(open parenthesis character)
構文クラス: 閉じ括弧文字(close parenthesis character)

開き/閉じ括弧文字は, 文や式を囲む相異なる対として使われる文字である. そのようなグループ化は, 開き括弧文字で始まり閉じ括弧文字で終る. 各開き括弧文字は特定の閉じ括弧文字に対応し, その逆もいえる. Emacsは, 通常, 閉じ括弧文字を挿入すると 対応する開き括弧文字を短時間指し示す. see section 括弧を点滅する.

開き括弧文字クラスは‘(’で指定し, 閉じ括弧文字クラスは‘)’で指定する.

英文向けのテキスト(text)モードとCモードでは, 括弧の対は, ‘()’, ‘[]’, ‘{}’である. Emacs Lispでは, リストとベクトルの区切り(‘()’と‘[]’)は, 括弧文字としてクラス分けされる.

構文クラス: 文字列クォート(string quote)

文字列クォート文字(‘"’で指定)は, LispやCを含む多くの言語で文字列定数を区切るために使われる. 同じ文字列クォート文字が文字列の最初と最後に現れる.

Emacsの構文解析機能では, 文字列を1つの字句とみなす. 文字列内の文字の普通の構文的な意味は抑制される.

lisp向けのモードには文字列クォート文字が2つ, ダブルクォート(‘"’)と縦棒(‘|’)がある. ‘|’はEmacs Lispでは使わないがCommon Lispで使う. Cにも2つの文字列クォート文字, 文字列用のダブルクォートと文字定数用のシングルクォート(‘'’)がある.

英文はプログラム言語ではないので, 英文には文字列クォート文字はない. 英文でも引用符は用いるが, その内側の文字の普通の構文的な属性を 抑制したくないのである.

構文クラス: エスケープ(escape)

エスケープ文字(‘\’で指定)は, Cの文字列や文字定数で使われるようなエスケープシーケンスを開始する. CとLispでは, 文字‘\’はこのクラスに属する. (Cではこの文字は文字列の内側だけで使われるが, Cモードでつねにこのように扱っても問題ないことがわかった. )

words-include-escapesnil以外であると, このクラスの文字は単語の一部分と解釈される. see section 単語単位の移動.

構文クラス: 文字クォート(character quote)

文字クォート文字(‘/’で指定)は, 後続の1文字をクォートし, 通常の構文上の意味を抑制する. 直後の1文字のみに影響するという点で, エスケープ文字と異なる.

words-include-escapesnil以外であると, このクラスの文字は単語の一部分と解釈される. see section 単語単位の移動.

このクラスは, TeXモードのバックスラッシュに使われる.

構文クラス: 対になった区切り(paired delimiter)

対になった区切り文字(‘$’)は文字列クォート文字と同様であるが, 区切り文字のあいだにある文字の構文上の属性を抑制しない点が異なる. 現在, 対になった区切りはTeXモードのみで使い, 数学モードに出入りする‘$’である.

構文クラス: 式前置子(expression prefix)

式前置演算子(‘'’)は, 式のまえに現れると 式の一部であるとみなされる構文上の演算子に使われる. lisp向けのモードでは, (クォートする)アポストロフ‘'’, (マクロで使う)コンマ‘,’, (ある種のデータの入力構文に使われる)‘#’の文字がそうである.

構文クラス: コメント開始(comment starter)
構文クラス: コメント終了(comment ender)

コメント開始文字とコメント終了文字は, さまざまな言語でコメントを区切るために用いられる. これらのクラスは, それぞれ, ‘<’と‘>’で指定する.

英文にはコメント文字はない. Lispでは, セミコロン(‘;’)でコメントが始まり, 改行かページ送りで終る.

構文クラス: 継承(inherit)

この構文クラスは特定の構文を指定しない. 標準の構文テーブルで当該文字の構文を探す指定である. この構文クラスは‘@’で指定する.

構文クラス: 汎用コメント区切り(generic comment delimiter)

汎用コメント区切り文字は, 特別な種類のコメントを 始めて終える文字である. 任意の汎用コメント区切り文字は 任意の汎用コメント区切り文字に対応するが, 普通のコメント開始文字/コメント終了文字には対応しない. 汎用コメント区切り文字同士のみで対応する.

この構文クラスは, 主にテキスト属性syntax-table (see section 構文属性)で使うことを意図したものである. 任意の範囲の文字がコメントを形成すると印を付けるには, その範囲の先頭と末尾の文字にそれらが汎用コメント区切りであることを 識別する属性syntax-tableを与える.

構文クラス: 汎用文字列区切り(generic string delimiter)

汎用文字列区切り文字は, 文字列を始めて終える. このクラスは文字列クォートクラスと異なり, 汎用文字列区切りは他の汎用文字列区切りに対応し, 普通の文字列クォート文字には対応しない.

この構文クラスは, 主にテキスト属性syntax-table (see section 構文属性)で使うことを意図したものである. 任意の範囲の文字が文字列定数を形成すると印を付けるには, その範囲の先頭と末尾の文字にそれらが汎用文字列区切りであることを 識別する属性syntax-tableを与える.


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34.2.2 構文フラグ

構文テーブルの各文字には, 構文クラスに加えて, フラグも指定できます. 文字‘1’, ‘2’, ‘3’, ‘4’, ‘b’, ‘p’で 表現される6つの可能なフラグがあります.

p’を除くすべてのフラグは, 複数の文字から成るコメント区切りの記述に 使います. 数字フラグは, 当該文字のクラスで表される構文上の属性に加えて, コメント列の一部分でもあることを示します. フラグはクラスや他のフラグとは独立であり, Cモードの‘*’のような文字のためにあります. Cモードの‘*’は, 句読点文字であるとともに, コメント開始列の2番目の文字‘/*でもあり, コメント終了列の最初の文字‘*/でもあります.

文字cに対して可能なフラグとそれらの意味を以下に示します.


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34.3 構文テーブル向け関数

本節では, 構文テーブルを作成/参照/変更するための関数について述べます.

Function: make-syntax-table

この関数は, 新たな構文テーブルを作成する. 英文字やコントロール文字の構文は標準の構文テーブルから継承する. 他の文字の構文は標準の構文テーブルからコピーする.

ほとんどのメジャーモードの構文テーブルはこのように作成する.

Function: copy-syntax-table &optional table

この関数は, 構文テーブルtableのコピーを作成しそれを返す. tableを指定しないと(あるいはnil), 現在の構文テーブルのコピーを返す. tableが構文テーブルでないとエラーを通知する.

コマンド: modify-syntax-entry char syntax-descriptor &optional table

この関数は, 文字charの構文指定を 構文記述子syntax-descriptorとする. 構文テーブルtableにおいてのみ構文を変更し, 他の構文テーブルは変更しない. tableのデフォルトはカレントバッファの構文テーブルである. syntax-descriptorで望みの構文を指定する. これは, クラス指定子で始まり, 必要に応じて釣り合う文字とフラグを含む文字列である. see section 構文記述子.

この関数はつねにnilを返す. 当該構文テーブルにおけるこの文字に対する古い構文情報は破棄される.

構文記述子の最初の文字が12個の構文クラス指定子の1つでないとエラーを通知する. charが文字でなくてもエラーを通知する.

 
【例】

;; 空白文字をクラス白文字にする
(modify-syntax-entry ?\  " ")
     ⇒ nil
;; $’を開き括弧文字にする
;;   対応する閉じる文字は‘^’である
(modify-syntax-entry ?$ "(^")
     ⇒ nil
;; ^’を閉じ括弧文字にする
;;   対応する開く文字は‘$’である
(modify-syntax-entry ?^ ")$")
     ⇒ nil
;; /’を句読点文字にする
;;   コメント開始列の最初の文字, および, 
;;   コメント終了列の2番目の文字にもする
;;   これはCモードで用いられる
(modify-syntax-entry ?/ ". 14")
     ⇒ nil
Function: char-syntax character

この関数は, 文字characterの構文クラスを指定子で表したもので返す. これは構文クラスのみを返し, 釣り合う文字や構文フラグは返さない.

charが文字でないとエラーを通知する.

つぎの例はCモードにあてはまる. 最初の例は, 空白の構文クラスが(空白で表現される)白文字であることを示す. 2番目の例は, ‘/’の構文が句読点であることを示す. これは, この文字がコメント開始/終了の一部分でもあることは示さない. 3番目の例は, 開き括弧は開き括弧クラスであることを示す. これは, この文字に釣り合う文字が‘)’であることは示さない.

 
(string (char-syntax ?\ ))
     ⇒ " "
(string (char-syntax ?/))
     ⇒ "."
(string (char-syntax ?\())
     ⇒ "("

ここでは, char-syntaxが返す文字を 見やすくするためにstringを用いた.

Function: set-syntax-table table

この関数は, tableをカレントバッファの構文テーブルにする. tableを返す.

Function: syntax-table

この関数は, 現在の構文テーブル, つまり, カレントバッファの構文テーブルを返す.


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34.4 構文属性

言語の構文を指定するに十分なほど構文テーブルに柔軟性がないときには, バッファ内の特定の文字の出現に対して構文テーブルに優先する テキスト属性syntax-tableを指定できます. See section テキスト属性.

テキスト属性syntax-tableの正しい値はつぎのとおりです.

syntax-table

属性値が構文テーブルであると, 文字のこの出現に対する構文を判定するために カレントバッファの構文テーブルのかわりにこのテーブルを用いる.

(syntax-code . matching-char)

この形のコンスセルは, 文字のこの出現の構文を指定する.

nil

属性がnilであると, 通常どおり, 現在の構文テーブルから文字の構文を判定する.

Variable: parse-sexp-lookup-properties

これがnil以外であると, 構文を解析する関数は, テキスト属性による構文指定に注意を払う. さもなければ, 現在の構文テーブルのみを用いる.


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34.5 移動と構文

本節では, 特定の構文クラスを持つ文字を越えて移動するための 関数について述べます.

Function: skip-syntax-forward syntaxes &optional limit

この関数は, syntaxesで指定される構文クラスを持つ文字を越えて ポイントを前方へ向けて移動する. バッファの末尾, (指定されていれば)limitの位置, 飛び越さない文字のいずれかに出会うと停止する. 戻り値は移動距離であり非負整数である.

Function: skip-syntax-backward syntaxes &optional limit

この関数は, syntaxesで指定される構文クラスである文字を越えて ポイントを後方へ向けて移動する. バッファの先頭, (指定されていれば)limitの位置, 飛び越さない文字のいずれかに出会うと停止する.

戻り値は移動距離である. それはゼロか負の整数である.

Function: backward-prefix-chars

この関数は, 式前置子構文の文字を飛び越えてポイントを後方へ向けて移動する. 式前置子クラスやフラグ‘p’を持つ文字を飛び越す.


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34.6 釣り合った式の解析

ここでは, 括弧が対になっているS式(sexp)とも呼ばれる 釣り合った式を解析したり走査する関数について述べます. 構文テーブルで文字の解釈を制御することで, LispモードではLispの式に対して, CモードではCの式に対して これらの関数を用いることができます. 釣り合った式を飛び越えて移動するための便利な上位レベルの関数については, See section 式単位の移動.

Function: parse-partial-sexp start limit &optional target-depth stop-before state stop-comment

この関数は, カレントバッファのstartから始まるS式を解析するが, limitを越えては走査しない. 位置limitで止まるか, 以下に述べる条件が満たされると解析を停止し, 当該箇所にポイントを置く. ポイントを置いた箇所での解析状況を表す値を返す.

statenilであると, 位置startは, 関数定義の先頭のような 括弧の構造のトップレベルであると仮定する. あるいは, 構造の途中から解析を再開したい場合もある. それには, 解析の初期状態を引数stateに指定する必要がある.

3番目の引数target-depthnil以外であると, 括弧の深さがtarget-depthに等しくなると解析を停止する. 深さは0, あるいは, stateで指定された値から始まる.

4番目の引数stop-beforenil以外であると, S式を始める文字に出会うと解析を停止する. stop-commentnil以外であると, コメントの始まりに出会うと解析を停止する. stop-commentがシンボルsyntax-tableであると, コメントや文字列の始まり, コメントや文字列の終りのいずれかに 出会ったあとで解析を停止する.

5番目の引数stateは9要素のリストであり, 以下に述べるようにこの関数の値と同じ形である. (9番目の最後の要素は省いてもよい. ) parse-partial-sexpの呼び出しの戻り値を, 別のparse-partial-sexpの呼び出しの解析状態の初期値に使ってよい.

結果は, 解析の最終状態を記述した9要素のリストである.

  1. 0から数えた括弧の深さ.
  2. ポイントを停止した箇所を含むもっとも内側の括弧式の開始位置. なければnil.
  3. 閉じている最後の完全な部分式の開始位置. なければnil.
  4. 文字列の内側であるとnil以外である. より正確には, これは文字列を終える文字である. あるいは, 汎用文字列区切り文字で終えるときにはtである.
  5. (どちらかの形式の)コメントの内側であるとtである.
  6. ポイントがクォート文字の直後であるとtである.
  7. この解析中に出会った最小の括弧の深さ.
  8. どの形式のコメントが活性であるかを表す. 『a』形式であるとnil, 『b』形式であるとt, 汎用コメント区切り文字で終るコメントの場合にはsyntax-tableである.
  9. 文字列やコメントの開始位置. コメントの内側であるときにはこれはコメントの開始位置であり, 文字列の内側であるときにはこれは文字列の開始位置である. 文字列やコメントの外側では, この要素はnilである.

引数stateでは, 要素0, 3, 4, 5, 7は重要である.

この関数は, 入れ子にあった括弧を持つ言語向けに 字下げを計算するためにしばしば用いられる.

Function: scan-lists from count depth

この関数は, 位置fromから前方へ向けてcount個の 釣り合った括弧のグループを走査する. 走査を停止した位置を返す. countが負であると, 後方へ向けて走査する.

depthが0以外であると, 括弧の深さをその値から数え始める. 停止箇所の候補位置は, 括弧の深さが0になる箇所である. scan-listsは, そのような箇所をcount回数えてから停止する. したがって, depthに正の値を指定すると, 括弧のレベルをdepthレベルだけ抜けることを意味する.

parse-sexp-ignore-commentsnil以外であると, コメントを無視して走査する.

走査がバッファ(あるいはその参照可能部分)の先頭や末尾に達し, 深さが0でないと, エラーを通知する. 深さは0であるが指定個数だけ数えてない場合には, nilを返す.

Function: scan-sexps from count

この関数は, 位置fromから前方へ向けてcount個のS式を走査する. 走査を終えた位置を返す. countが負であると, 後方へ向けて移動する.

parse-sexp-ignore-commentsnil以外であると, コメントを無視して走査する.

走査が括弧によるグループの途中で バッファ(あるいはその参照可能部分)の先頭や末尾に達すると, エラーを通知する. 指定個数だけ数えるまえに括弧によるグループのあいだで 先頭や末尾に達した場合はnilを返す.

Variable: parse-sexp-ignore-comments

値がnil以外であると, 本節の関数やforward-sexpは, コメントを白文字として扱う.

Emacsの古い版では, コメントの終了が‘*/’のような形であり, かつ, コメントの終了と思える場合にのみ, この機能は動作した. 改行でコメントを終える言語では, 改行すべてがコメントの終りではないために, この変数をnilにする必要があった. このような制限事項はすでにない.

forward-commentを使うと, 1つのコメントや複数のコメントを飛び越えて前後に移動できます.

Function: forward-comment count

この関数は, ポイントを前方へ向けて(countが負ならば後方へ向けて) count個のコメントを飛び越えて移動する. コメントか白文字以外のものに出会うと停止し, 当該箇所にポイントを置く. count個だけ数えたあとにももちろん停止する.

ポイントに続くすべてのコメントと白文字を飛び越えるには, (forward-comment (buffer-size))を使います. バッファ内のコメントの個数は(buffer-size)を越えるはずがないので, 引数に使うには(buffer-size)はよいものです.


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34.7 標準的な構文テーブル

Emacsのほとんどのメジャーモードにはそれ独自の構文テーブルがあります. それらのいくつかをつぎに示します.

Function: standard-syntax-table

この関数は, 基本(fundamental)モードで使用する構文テーブルである 標準の構文テーブルを返す.

Variable: text-mode-syntax-table

この変数の値は, テキスト(text)モードで使用する構文テーブルである.

Variable: c-mode-syntax-table

この変数の値は, Cモードのバッファ向けの構文テーブルである.

Variable: emacs-lisp-mode-syntax-table

この変数の値は, 編集コマンドがemacs-lispモードで使用する構文テーブルである. (これはLispの関数readにはなんの効果もない. )


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

34.8 構文テーブルの内部

Lispプログラムでは普通は構文テーブルの要素を直接には操作しません. Lispレベルの構文テーブル関数は, 普通は構文記述子(see section 構文記述子)を操作します. ですが, 内部形式を明文化しておきます.

構文テーブルの各要素は, (syntax-code . matching-char)の 形のコンスセルです. CARsyntax-codeは, 構文クラスと構文フラグを符号化する整数です. 釣り合う文字を指定してあると, CDRmatching-charnil以外です.

つぎの表は, 各構文クラスに対応するsyntax-codeの値です.

整数 クラス整数 クラス整数 クラス
0    whitespace5    close parenthesis10    character quote
   白文字   閉じ括弧   文字クォート
1    punctuation6    expression prefix11    comment-start
   句読点   式前置子   コメント開始
2    word7    string quote12    comment-end
   単語   文字列クォート   コメント終了
3    symbol8    paired delimiter13    inherit
   シンボル   対になった区切り   継承
4    open parenthesis9    escape14    comment-fence
   開き括弧   エスケープ   コメント区切り
15   string-fence
   文字列区切り

たとえば, ‘(’の普通の構文値は, (4 . 41)です. (41は‘)’の文字コード. )

フラグは, 最下位ビットから16番目のビットから始まる上位ビットに符号化します. つぎの表は, 各構文フラグとそれに対応する2の巾です.

フラグ 2の巾フラグ 2の巾フラグ 2の巾
1’    (lsh 1 16)3’    (lsh 1 18)p’    (lsh 1 20)
2’    (lsh 1 17)4’    (lsh 1 19)b’    (lsh 1 21)


[ << ] [ >> ]           [冒頭] [目次] [見出し] [ ? ]

この文書は新堂 安孝によって2009年9月22日texi2html 1.82を用いて生成されました。