autoconf 学び直し その3

autoconfの学び直し、その3回目。

以前いじくった時は特に難しいことを必要としなかったので、キチンとメモを残しておかなかったので、ちゃんと残す。

環境によって挙動を変えるように設定したい。

前回は m4 マクロに手を付けた。
今回も引き続き m4 マクロを勉強する。

前回の参考文献


- Super Technique 講座〜m4 チュートリアル
-- http://www.nurs.or.jp/~sug/soft/super/m4.htm

復習


- m4とは?
-- 汎用的なマイクロプロセッサなのだそうだ
- m4の組み込み関数は「ディレクティブ」と呼ばれる。
- define() : マクロ定義に関するディレクティブ
- m4のトークンの表記はC言語の変数の表記とルールが同じ
-- 大文字と小文字は当然区別される
- 変換後の文字列をトークン扱いでき、defineでさらにマクロ置換ができる場合は、どこまでも置換をする
define(`XXX', `YYY YY')
define(`YYY', `ZZZ')
one two three : XXX.



one two three : ZZZ YY.


- indir() : 強制的に置換

- マクロは改行を含んでいてもOK。m4は執念深く「'」を探す
- クォート「`'」は文字列をトークンで無くす
- m4はマクロへの変換が終了したら、1重だけ「`文字列'」を「文字列」に変換する
- マクロに変換した文字列がトークンになって欲しくない場合は、マクロ定義で文字列を2重クォートすれば良い。
- テキスト側にクォートを仕込む事ができる。
- m4はCと同じく引数付きマクロが定義できる
-- 引数に$0, $1, ...のような名前がつく
--- $0 : マクロの名前
--- $# : 引数の個数
--- $* or $@ : すべての引数を「,」で結合したもの
- m4の引数付きマクロは、引数の過不足に警告を出さない
-- 多すぎる場合は無視をする。少ない場合には空文字列になる。

define(`echo1',`$*')
define(`echo2',`$@')
define(This,That)
echo1(`This',`is',`a',`pen')
echo1(``This'',`is',`a',`pen')
echo2(`This',`is',`a',`pen')
echo2(``This'',`is',`a',`pen')



That,is,a,pen
This,is,a,pen
This,is,a,pen
`This',is,a,pen

になる。

今回の参考文献


- Super Technique 講座〜m4 チュートリアル
-- http://www.nurs.or.jp/~sug/soft/super/m4.htm
- GNU macro processor:
-- http://www.bookshelf.jp/texi/m4/m4-ja.html#SEC_Top

今回


undefine, pushdef, popdef

- defineと対応するundefineがある
- defineしたマクロ定義を、一時的なマクロ定義で変更し、その後さらに変更を取り消すことができる
-- pushdef, poudefを使う

define(`XXX',`YYY')
XXX is YYY.
pushdef(`XXX',``XXX'')
But XXX is XXX.
popdef(`XXX')
So XXX is YYY.
undefine(`XXX')
But XXX is XXX.





YYY is YYY.

But XXX is XXX.

So YYY is YYY.

But XXX is XXX.

に変換される。

include, sinclude

- 別ファイルに記述した内容を展開できる
-- includeは指定したファイルが存在しないときにはエラーになる
-- sincludeは指定したファイルが存在しないときもエラーにならない
- includeとsincludeはマクロ定義に組み込める
-- sincludeしたファイルが無ければ空白文字になる

例、
- 最初に「echo "hello hello hello" > hello.m4」などとしておく

include(`hello.m4')
define(`hello',sinclude(`hello.m4'))
define(`hey',sinclude(`hey.m4'))
hello
good bye
hey
hello


hello hello hello

hello hello hello
good bye

hello hello hello

になる。

条件分岐 : ifdef, ifelse

- ifdefディレクティブ
ifdef(NAME,IF-CASE,ELSE-CASE)


-- 動きを見ると理解が速い

-- 例、事前にcond.m4を用意する
--- cond_ifdef.m4
ifdef(`COND',``COND' is defined...
`COND' is COND.',`COND is *NOT* defined!')


--- その後、コマンドラインで実行
--- 「COND is」がCONDの値に左右されないよう、2重クォートされている。
% m4 cond_ifdef.m4
COND is *NOT* defined!
% m4 -DCOND cond_ifdef.m4
COND is defined...
COND is .
% m4 -DCOND=conditionA cond_ifdef.m4
COND is defined...
COND is conditionA.


- ifelseディレクティブ
ifelse(比較対象A,比較対象B,一致時に展開[,不一致時に展開])

- ifdefが調べる変数名を記述したのに対し、ifelseは比較対象を書く
-- そのため、ifelseでは値を評価するために、比較対象の変数名をクォートでくくらない

-- 例、事前にcond.m4を用意する
--- cond_ifelse.m4
ifelse(COND,1,``COND' is one',``COND' is COND')


-- その後、コマンドラインで実行
--- 「COND is」がCONDの値に左右されないよう、2重クォートされている。

-- $ m4 -DCOND=1 test.m4 の場合

COND is one


-- $ m4 -DCOND=2 test.m4 の場合

COND is 2


- 不一致時に展開されるトークンを記述できるが、トークンの変わりに、ifelseディレクティブを入れ子にできる

--- cond_ifelse.m4
ifelse(COND,1,``COND' is one',COND,2,``COND' is two',``COND' is COND')


-- $ m4 -DCOND=1 test.m4 の場合

COND is one


-- $ m4 -DCOND=2 test.m4 の場合

COND is two


-- $ m4 -DCOND=3 test.m4 の場合

COND is 3


shift : 不定引数をリストとして扱う

- shift は引数のうち第一引数を無視して、第2引数以降だけを返す。

shift()
shift(foo)
shift(foo,bar,baz)





bar,baz

になる。

ループ

- m4はマクロで再帰が書ける
- defineとifelseとshiftを使うのが定石

define(`last',`ifelse($#,1,$1,`last(shift($@))')')
last(foo,bar,baz,piyo)



piyo

になる。

もしも
define(`last',`last(shift($@))')
last(foo,bar,baz,piyo)

にすると、shiftが戻す引数が減り続け、永遠に空白が生まれつづけるので無限ループになる。

引数を逆順に表示するには以下のようにする
define(`reverse',`ifelse($#,1,$1,`reverse(shift($@)) $1')')
reverse(foo,bar,baz,piyo)



piyo baz bar foo


引数の加算と減算 : incrとdecr

incr(整数)とかdecr(整数)とかできる。
++と--な。

changequote : クォートの開始文字列と終了文字列の入れ替え

- changequoteすれば、m4で処理するファイルを記述したプログラミング言語の記法とぶつからないクォート文字列を設定できる。
- 標準はchangequote(`,')したのと同じ状態になっている
- 文字列なので単一の記号じゃなくても大丈夫

changecom : コメントの開始文字列と終了文字列の変更

- m4のコメントは標準では「#」から改行まで
- changecom(開始コメント文字列,終了コメント文字列)
- コメント扱いされた文字列はマクロ展開されない
- ただしコメントは出力される。

dnl : 以降を改行まで無視する

- dnlディレクティブ以降、改行までの出力を抑制する。改行も出力されない
- ディレクティブの末尾にdnlをつけると、末尾の改行を抑制きるので、ディレクティブの変換後に空行が生まれない。

X
define(`X',`test')
X
define(`X',`test')dnl
X
define(`Y',`test dnl
test')dnl
X


X

test
test
test test

になる。

- dnlというトークンを表示したいときは、クォートで囲む

「-P」オプション(or --prefix-builtins)

- すべての組み込みディレクティブ名が「m4_」から始まることになる

m4はC言語のヘッダファイルを処理できるか

- m4ではC言語とバッティングしそうなディレクティブ名は引数がないと無視される
-- include, define, ifdef などいろいろ
- 「#」がm4のコメント扱いされるので「#define」や「#include」などを処理したければchangecomする

emacsと同じ正規表現による置換、削除 : patsubst

- patsubstはemacsの正規表現で文字列を探索し、置換や削除を行なえる
- patsubst( 対象文字列, 正規表現, 置換文字列 )で置換
- patsubst( 対象文字列, 正規表現)で削除

define(`X',`this is a pen')
patsubst(X,`\b',*)
patsubst(X,`\w+',*\&*)



*this* *is* *a* *pen*
*this* *is* *a* *pen*

になる。

**** emacsの正規表現
- emacsには語という概念がある。あとでやり直すけど、スペース区切りなのかな。
-- と思ったけど[0-9a-zA-Z_]で表現できるのが「語」かな
- \< : 語の先頭
- \> : 語の末尾
- \b : 語の先頭または末尾
- \w : 語を構成する文字([0-9a-zA-Z_])
- \& : 一致部分を表すシンボル

translit : 字単位の置換

- translit( 対象文字列, 対象字種, 置換字種)
- perlの「=~ tr///」的な

define(`X',`this is a pen')
translit(X,`a-z',`A-Z')



THIS IS A PEN

になる。

部分一致文字列を取得できる正規表現ディレクティブ : regexp

- regexpは開始記号「\(」と終端記号「\)」の間の正規表現とマッチした文字列を取得できる。
-- 1番目の部分文字列が/1、2番目は/2、3番目は、、、となる。

len

- 文字列の長さを取得

len()


0

になる。

len(`abcdef')


6

になる。

index

- 対象文字列中に検索用文字列が出現するか、出現するとしたら何文字目かを調べる

index(`gnus, gnats, and armadillos', `nat')
=>7
index(`gnus, gnats, and armadillos', `dag')
=>-1


substr

- 部分文字列を取得するときに使う

substr(`gnus, gnats, and armadillos', 6)
=>gnats, and armadillos
substr(`gnus, gnats, and armadillos', 6, 5)
=>gnats


syscmd, esyscmd, sysval

- シェルでコマンドを実行したいが、実行結果の標準出力を取得しなくて平気な時はsyscmd
- シェルでコマンドを実行し、実行結果の標準出力を取得するならesyscmd
- シェルコマンドの実行化を取得するならsyseval

eval

- 整数式の計算に使う




以上、m4の入門編をざっと終わらせた。
今後は他のアプリのm4ファイルを読んでみる。

emacsの正規表現を知らないので、後日調べる。


投稿者:としのり  日時:23:59:59 | コメント | トラックバック |
blog comments powered by Disqus