拡張/似非Cプリプロセッサ acpp v0.95 by tenk* ■ はじめに このプログラムは、Cコンパイラの前処理を行う cpp を独自拡張したもの で、masm等のアセンブラのマクロを真似た、 #macro 〜 (#local) 〜 #endmacro #rept 〜 #endrept #ipr 〜 #endipr 等の命令を加えたものです。 といっても cpp の替りに使うというより、# の替りに @ $ . ? に変更可能 なので、どちらかといえばアセンブラへの利用のほうが有用かもしれません。 例えば68kアセンブラ用ならば .if〜.endif @if 〜 @endif .macro〜.endm @macro 〜 @endm のような擬似命令になり条件アセンブルやマクロのないアセンブラのプリプロ セッサとして使えるでしょう。(多少アセンブラの文法との整合性がとれない かもしれませんが) もともと別のプログラム、独自表記のアセンブラプリプロセッサを作ってい てそのマクロ機能部分のみを独立させ強引に cpp に似せたものです:) 一応、LSI-C86試食版のオプションにちょこっと似せたつもりです. ■ つかいかた (および できること) usage> acpp [-options] filename [-options] filename は読み込むファイル。 複数指定された場合は、順次読み込み、繋がったソースとして扱います。 オプション (できること) -i[DIR] include 時に詮索するディレクトリを指定. -iは複数指定可能. また DIR は;で区切って複数を記述可能。 -o[FILE] 出力ファイル名 -d[NAME] #define NAME 1 をする -d[NAME=STR] #define NAME STR をする -u[NAME] #undef NAME をする -s 元ソースをコメントにして出力しない(-pc0に同じ) -w 無視 @[FILE] レスポンスファイル FILE より オプション、ファイル名を取得. レスポンスファイル中では、; がコメント開始文字になります。 -c[FILE] acpp.exeと同じディレクトリよりレスポンスファイルFILE[.CFG] を読み込む. なお、指定なくとも、acpp.exeと同じディレクトリのacpp.cfgは 自動で読みこみます。 -? ヘルプ -p -p関係のオプションのヘルプ. 現在の設定を確認できます. -p? -p関係のオプションのヘルプ. 現在の設定を確認できます. -pm[C] #の替りにマクロ開始文字を C にする. C は # $ @ ? . -pmm[C] #の替りにマクロ開始文字その2 を C にする. C は # $ @ ? . -pl[C] C をラベルを構成する文字とする. C は # $ @ ? . -pn[C] C をラベルを構成する文字としない. C は # $ @ ? . -pp[NAME] #local で生成するラベルのプレフィックス -pc[N] 元ソースをコメントにして出力 0:しない 1:する( ; ソース行) 2:TAG形式(filename line : ソース行) にする 3:# 行番号 ファイル名 を出力 -pcs[STR] -pc1|2 時、ソースのコメント化で';'の替りにコメントの 行頭につける文字列 -pce[STR] -pc1|2 時、ソースのコメント化でコメントの行末につける 文字列 -pcs"/*" -pce"*/" とすれば /* ソース */となるのを想定. -pe[C] C をコメント開始キャラとする(2個可) -pet[C] C を行頭のみのコメント開始文字とする(2個可) (68系の行頭の * コメント対策) -py[N][t] ''""中の\文字を特別扱いに 0:しない 1:する t付:変換もする -ps[-] //コメントを有効にする -ps- しない -pb[-] /*コメント*/を有効にする -pb- しない -pf[-] \改行コードによる行連結をする -pf- しない -pt[-] 空白の圧縮をする -pt- しない -pj[-] MS全角に対応する -pj- しない -po[-] 0で始まる数を8進数にする -po- しない -prd[-] $の扱いを16進数開始文字とする -prd-しない (-prq[-] 'を対でなく、'C で 68xxアセンブラ用にする) 廃止予定 -pq[N] '文字'を 0:無効 1:ペア''で有効 2:'aのように1個で有効(68xxアセンブラ対策) -pqw[N] "文字列定数"を 0:無効 1:有効 -pd 数値(31,0x3,0b10,077,'a'等)を十進数に変換 ソースに小数点数とかが混ざってると不幸だし、よほどのことで ない限り指定する必要のないオプション. (-p関係の)デフォルトオプションは、-p? で表示すれば現在の設定が 表示されるのでそれで確認できます。 一応, -pm# マクロ開始文字は # -pmm# マクロ開始文字その2は # -pf \による行連結あり -ps,-pb //コメント /*コメント*/ は有効 -pj MS全角対応 -pt- 空白の圧縮なし -pc3 #行番号 ファイル名 を出力 -py1 \文字を特殊文字とする(変換はしない) -pq1 '文字'有効 -pqw1 "文字列有効"有効 -pp_LCL_ となっています。 -p 関係のオプションは、コンフィグファイルに定義して置くのを想定しています。 ■ 文法 □ コメント コメントには、改行に関わらず囲まれた範囲を無視する/* コメント */ と, 行末改行までを無視する //コメント があります。 -pb-, -ps- を指定すると、コメント機能を禁止することができます。 (ただし //コメントは #行では -ps-の指定の有無に関わらずコメントとして 機能します) また、-pe,-pet が指定されていれば、その文字から改行までをコメントと します. □ 定数 2進数 0bで始まり、0,1からなる数字列 または0,1で始まり0,1が連なり最後にBが付く文字列 8進数 0で始まり 0〜7からなる数字列(-poの場合のみ) 10進数 1〜9で始まり0〜9からなる数字列 16進数 0xで始まり、1〜9,A〜Fからなる数字列 または0〜9で始まり1〜9,A〜Fが連なり最後にHが付く文字列 (-prd指定時は $で始まり 0〜9,A〜Fからなる数字列) これらは、途中に _ があってもかまいません(無視する) □ 文字定数 '文字' のように 'で囲むと、その文字コードを値とします. C言語と違い、'ABCD' のように8バイトまで複数文字が指定でき, その場合は, 'A'*0x1000000+'B'*0x10000+'C'+0x100+'D' と同じになります。 全角に対応しています. なお、-pq2 が指定されている場合は 'C で1バイトのみの文字定数として 扱われます(6809のアセンブラ対策). □ 文字列 "文字列" のように " で囲ったものが文字列となります。 隣接文字列の合体は行いません. □ ""''中の\文字 '文字定数'、"文字列"中で指定できる特殊機能文字です. (それ以外のところでは認識しません) \で始まります。 オプション -py で、この機能を有効にするかどうかを指定できます. コード 役目 \n 0a LF. \r 0d CR. \N 0d0a \r\n におなじ. \a 07 アラーム. \b 08 BS. \f 0c 改項. \e 1b エスケープシーケンス文字. \t 09 タブ. \v 0b 垂直タブ. \\ 5c \自身. \' 27 '自身. \" 22 "自身. \0 00 文字コード 0. \OOO O は 8進数文字. 3桁まで. \xHH H は16進数文字. 2桁まで. \XHHHH H は16進数文字. 8桁まで. □ 定数式 cpp と同様な演算子があります. 単項- 単項+ () ~ ! defined(ラベル) * / % + - >> << > >= < <= == != & ^ | && || defined は#で始まる行かマクロ中でしか使用できません。 □ 命令 (-pm で設定された文字)#で始まる行頭のプリプロセッサ命令。 ○ #include ファイル名 #include "ファイル名" #include <ファイル名> ファイル名よりテキストを読み込みます。 基本的には、まずカレントディレクトリを検索し、なければ -iで 指定されたディレクトリを順次検索します。 <ファイル名> で指定された場合は、カレントの検索を行わず、-i で 指定されたディレクトリのみ、検索します。 ○ 条件コンパイル #if文 ・#if 式 : : #endif 式の計算を行った結果、0以外ならば #if〜#endifの間の文を生成します. ・#if 式 : : #else : : #endif 式の計算を行った結果、0以外ならば #if〜#elseの間の文を,0ならば #else〜#endif の間の文を生成します. ・#if 式1 : : #elif 式2 : : #elif 式3 : : #else : : #endif #if,#elif(複数可)の式を上から順に計算し、0以外だったらその間の テキストを生成し、そうでく#else があれば、その文を生成し、なけ れば生成しません。 なお条件式の計算は、符号付き32ビット整数で行われます. ・すでにあるアセンブラ・ソースに用いるとき、ソースの変更個所を 減らすため, 以下の命令を一応用意しています. #ifne,#ifeq,#ifge,#ifgt,#ifle,#iflt #ifne は #if に同じ. #ifeq は #if (条件式) == 0 に同じ #ifge は #if (条件式) >= 0 に同じ #ifgt は #if (条件式) > 0 に同じ #ifle は #if (条件式) <= 0 に同じ #iflt は #if (条件式) < 0 に同じ ・#ifdef LBL ,#ifndef LBL #ifの替りに用いられる. #ifdef LBL は LBL が定義されていれば真になる。#if defined(LBL)に同じ #ifndef LBL は LBL が未定義ならば真になる。 #if !defined(LBL)に同じ ○ #define マクロ #define ラベル名 文字列 #define ラベル名(引数) 文字列 ラベル名が使われると 対応する文字列に置き換わります。 引数があれば、変換文字列中の引数名が、指定された引数と 置換されます. ○ #undef #undef ラベル名 ラベルが #define,#set,#macro で設定された名前ならば、未定義状態に もどします。未定義のラベルの場合は何もしません。 ※#reptや#iprの中で ラベルを再定義するために, #defineとペアにして #rept,#ipr中に用いるのはしないでください。展開順序の都合により 意図したとおりは展開できません。バグですが仕様です:-) ○ #set 定義 #set ラベル名 = 定数式 #define と似たものですが、この行で定数式が計算され、ラベル名が 使われると、数字列に置き換わります。 また、#define と違い #set は同じラベル名に対し #undef の必要なく 何度でも行うことができます。 ○ #macro マクロ ・#macro マクロ名 : : #endmacro または #endm #macro マクロ名(引数名1, 引数名2) #local ラベル1,ラベル2 : : #exitmacro または #exitm : : #endmacro マクロを定義します。マクロ名がつかわれると、 #macro〜#endmacro(#endm)までの内容を生成します. 引数付きで宣言すれば、引数名が置換されます。 #exitmacro(#exitm) で、マクロの展開を中止できます。 また、#if,#rept,#iprをその内側で使用可能です. #local 文があると、指定されたラベル名は、 展開時に、衝突しないよう別の名前が生成されます。 デフォルトでは _LBL_数字 のような名前に置換されます。 ・#macro #local ラベル1,ラベル2 : : #endmacro マクロ名の無い場合、その場でマクロ展開します。 たんに特定範囲で#local命令を使いたい場合を想定しています。 ○ #rept ・#rept 回数 : : #endrept または #endr #rept〜#endrept(#endr) の間の行を 指定回数生成します. ・#rept ラベル名=回数 : : #endrept #rept〜#endreptの間の行を 指定回数生成します. その回数を ラベル名により参照できます。番号は 0..n-1までです. ネスト可能です。 ○ #ipr #ipr ラベル名=置換1,置換2,・・・置換n : : #endipr #ipr 〜 #endipr の中を置換文字列がある間繰り返します。 ラベル名は、各ループに対応する置換文字列によって置換されます。 ネスト可能です。 ○ #error #error 文字列 エラーメッセージ用. 文字列を標準エラー出力します。 ○ #print #print 文字列 デバッグ用。文字列を標準出力します。 ○ #file ○ #line ○ #pragma 無視します. □行頭以外での(-pmm で設定された文字)#の機能. cと同様 #,## が特殊な働きをします。 ただし #で始まる行かマクロ中でのみ有効です. #NO の場合、"NO" を生成し、 str##NO の場合, strNO を生成します。 もし NO がマクロまたはマクロの引数の場合で 10が設定されていれば #NO は "10"になり, str##NO は str10 になります. Cにはない機能として #(定数式) で定数式の計算結果の値の文字列を生成します. たとえば #(0x20*10) ならば 320 に置き換わります. ただしこれも#行やマクロ内のみです. これらの機能のみ -pmm オプションで別文字設定ができるようになっています。 というのは、-pm. のようにして行頭のみの命令を .if .macroとしてアセンブラ ソースに用いたりした場合、そのままではこれらの機能は .NO や str..NO や .(式)のようになってわかりずらくなるため, 別の文字(@ や $, ?) で代用する ためにあります。 □ 特殊マクロ名 cpp にある __FILE__ 現在のファイル名 __LINE__ 現在の行数 __DATE__ 現在の日付 __TIME__ 現在の時間 は、acpp にもあり、使用すると同様に展開されます。 ■ 内部処理の都合 このプログラムは、もともと他のプログラムを作る過程での副産物的 なもので、cpp に似せてはいますが、行志向をそれほど重要視していな かったため、C言語と同じトークン切り分けならば問題ないですが、 そうでない場合、不都合があるかもしれません。 動作としては、一旦、acppでのトークンに切り分け、マクロ等を処理し たのち再度繋げなおすという感じになります。 とくに問題になるのは、"文字列" '文字列' の扱いで、" や 'の扱い が違うモノや 文字列を表すのに " や '以外を用いるモノのプリプロセス に使うには、マクロ展開のことを考えると、ちと注意がいるでしょう。 (一応オプション -pq0や -pqw0で ' や "の機能を抑止できますが、代わ りの文字列指定はありません) メモリが十分あることを前提に作っているので結構メモリ食いです。 マクロ(macro,define)やループ(rept,ipr)は展開しもって出力してい るのでなく、一旦メモリへ展開したのち出力しており、その展開先メモリ サイズが固定で、だいたい190Kバイトくらいまで、となっています。 ので、極端に複雑で大きなマクロやループでは使用できない場合があり ます。 ■ サンプル 68Kアセンブラ用にプリプロセッサを設定するばあいの定義ファイル例です. ------------------------ キリトリセン -------------------------------- ; 68000アセンブラ用の定義 -pm. ; . は特殊文字その1だ -pmm@ ; @ は特殊文字その2だ -pn# ; # はただの文字だ -pn$ ; $ はただの文字だ -pn@ ; @ はただの文字だ -pl? ; ? はラベルにできる文字だ -pc2 ; 出力には元ソース行も含める(TAGファイル形式). -pcs* ; そのソース行のコメント化で使うコメント文字は * -pe; ; ; をコメント開始文字とする -pet* ; 行頭のみのコメントとして * を認識 -py0 ; \文字を特殊文字としない -pf- ; \改行の連結を行わない -ps- ; //コメントを禁止する -pb- ; /*コメント*/を禁止する -po- ; 0で始まる数字は10進数だ -prd ; $で始まる16進数を認識する($00) ;さらに 6809 用にするばあいは,以下の行を追加 ; -pq2 ; モトローラアセンブラな 'の使い方.('A) ------------------------ キリトリセン -------------------------------- 実際の使用では、acpp.exe を app68k.exe に変名したものと定義ファイルを app68k.cfg としたものをパスの通った同じディレクトリにおいて使うのが よいでせう。 これで、.define .if .macro .local .rept .ipr の名で使え、 @ @@ で文字列化や名前文字連結とかできます. ■ 配布条件等 フリーソフトウェアです。 パソ通/インターネット等での非営利配布ならば 作者に連絡不要で再配布していただいてかまいません。その他の場合(雑誌 紹介とかディスク配布で同梱したいなど)事前に相談ください、ってことで。 営利配布は自由でない(要相談)ですが、営利利用(仕事場で業務に使うとか) はもちろん構いません。 ソースについては、下記条件を満たす限り、改造するなり流用するなり 自由で連絡不要ですし、流用の場合はマニュアル等に明記する必要は ないです。ただしソース公開の場合はソースの配布条件をどこかに書い てください。 ・acpp.exe の直接の改造物ならば、バージョンナンバーを原作者とは 別ものと見分けられるようにすること。 ・ルーチンの流用/改造では、最低限、流用ルーチンは、作者と同じ条件 を継続すること。 ・変更/追加等してその特許や著作権等で他者のプログラミングを制限し ないこと。変更箇所かどうかに関わらず他者のプログラミングを制限 するプログラムへのルーチンの流用を行わないこと。 他人のプログラミングを邪魔しないのであれば、別に市販ソフトだろ うとシュアウェアだろうと流用してよいです。 ・自分の変更を独り占めにしたいなら、公開しないこと。また、他者が 同様なコトを行っていても権利を主張しないこと。 なお、配布ファイル中の実行ファイルは Borland社の bcc32 v5.5 でコン パイルしてあります。 当然のことながら無保証です。作者はなんら義務を負いません。 利用者の責任で用いてください。 (バグがありましたら、連絡くださると助かります。でも、取れるとは 限らないですし、すぐさまデバッグにかかれるかどうかも不明です) ■ おわりに 本来の目的の独自表記アセンブラ(プリプロセッサ)の制作をなんとかしないと... と想いつつ、もうン年ごしの目標(^^; 文法とかの仕様はちょくちょく考えて楽しむんだけど、なかなかコーディング までこぎ着けない.ああ. この acpp だって、実際作ってから結構たつし. その割には、使うたんびに バグに遭遇して虫取り三昧かも^^; 今見るとかなりヘボイ作りなのでメンテ無限大か^^; 作りなおしたくなる けど...(ループ展開やマクロ展開の順番とかT T)... 大バグに出会うまではこれで我慢、と.  (……と、書いてたけれど、おおバグだらけでした^^; ) cpp の代わりに使うことはまずないですが、アセンブラのプリプロセッサ や自作ツールのプリプロセスとしては、ちょこちょこ使ってる、てとこかな. (もともと素な68Kアセンブラにマクロがほしくて急遽流用したんだし... 実際には filn.c を使うってことになるけれど... acppにしろdcasmにしろ、 filn.c のサンプルプログラムだなあ, てもんですが) だもんで、ANSI-Cの cpp との互換性とかはあまり気にしてないですし。 まだまだ、バグがいるだうけど、とりあえず。 tenk* (北村雅史) NBB00541@nifty.ne.jp