しょぼいマシンで自作プログラミング言語を作ってみる (5)
文字コードといっても色々あるけれど?
とりあえず、サポートしたいもの……
最低限、ASCIIとUTF-8、UTF-16、UTF-32はサポートしたいです。 それとできればShift-JIS、EUC-JPもサポートできるならしたいです。
ですが、C++によるコンパイラ実装の段階ではASCIIのみサポートする形とします。
ASCIIの文字コードはgallop言語でセルフホスティングコンパイラができたタイミングでサポートすることとしましょう。
まずは手っ取り早く検知できるものから検知
BOM付きファイルの検知
UTF-7、UTF-8、UTF-16、UTF-32においては、ファイルの冒頭にBOM(バイト順マーク)なるものをつけて、このファイルがどういう形式のファイルかを宣言することができます。
UTF-7は4種類あります。
先頭4バイトが0x2b、0x2f、0x76、0x38。文字列にすると”+/v8”です。
先頭4バイトが0x2b、0x2f、0x76、0x39。文字列にすると”+/v9”です。
先頭4バイトが0x2b、0x2f、0x76、0x2b。文字列にすると”+/v+”です。
先頭4バイトが0x2b、0x2f、0x76、0x2f。文字列にすると”+/v/”です。
UTF-8は1種類です。
先頭3バイトが0xef、0xbb、0xbfです。
UTF-16は2種類です。
先頭2バイトが0xfe、0xffです。これを指定するとビッグエンディアンで出力されているものとして解釈します。
先頭2バイトが0xff、0xfeです。これを指定するとリトルエンディアンで出力されているものとして解釈します。
UTF-16は2種類です。
先頭4バイトが0x00、0x00、0xfe、0xffです。これを指定するとビッグエンディアンで出力されているものとして解釈します。
先頭4バイトが0xff、0xfe、0x00、0x00です。これを指定するとリトルエンディアンで出力されているものとして解釈します。
エンディアンとはなんぞや?
エをイに変えてはいけません。センシティブな話になってしまうのです。 そんな余談はさておきエンディアンとはなにか。バイト列の配置順序のことです。 0x12345678という4バイトのバイト列を例にしますと、ビッグエンディアンは12345678という順に配置することをいい、リトルエンディアンは78563412という順に配置することをいいます。
BOMが検知できたら7ビット文字の文字の検知
7ビット文字コードには何がある?
7ビット文字の検知をしましょう。7ビット文字コードは俗に言うASCIIコードと言われるもので0x00から0x7fまでの文字のみを使用したものとなります。 また、7ビット文字だけを利用した文字コードはASCIIだけではなく、UTF-7、修正UTF-7も含まれます。
ASCIIコードの検知
あくまでファイルの文字コードを検知するという前提で話を進めるため、ASCIIコードのみで生成されたファイルには文字列の終端を示すヌル文字(0x00)が含まれていないこととします。 そのうえでASCIIコードを検知する仕様としては以下となります。
印字可能文字が含まれること。印字可能文字は0x20(半角空白)から0x7e(~(半角チルダ))までです。
改行、水平タブの制御コードが含まれること。改行は0x0a(LineFeed)、0x0d(CarriageReturn)です。古来のMacOSは0x0dのみが、Unix系OSは0x0aのみが、MS-DOS、Windowsは0x0d、0x0aの組み合わせで改行をしています。水平タブは0x09です。
上記2以外の制御コードが含まれている場合はASCIIコード以外であるとします。
UTF-7、修正UTF-7の検知
そもそもUTF-7とはEメールのための規格だったようです。
UTF-7の仕様は以下となります。
数字(0x30から0x39)、英大文字(0x41から0x5a)、英小文字(0x61から0x7a)、改行(0x0a、0x0d)、水平タブ(0x09)、半角空白(0x20)、9つの記号(シングルクォートーーアポストロフィとも言われますが、以降はシングルクォートで通しますーー(0x27)、開丸括弧 (0x28)、閉丸括弧 (0x29)、カンマ(0x2c)、ハイフン(0x2d)、ドット(0x2e)、スラッシュ(0x0f)、コロン(0x3a)、 クェスチョンマーク(0x3f))が含まれること。
上記1以外の文字はプラス(0x2b)とハイフン(0x2d)の間にBase64でエンコードされていること。プラス(0x2b)とハイフン(0x2d)が連続した場合はデコードした際にプラス(0x2b)になります。
上記2でいうところのBase64エンコードされた文字は数字(0x30から0x39)、英大文字(0x41から0x5a)、英小文字(0x61から0x7a)、プラス(0x2b)、スラッシュ(0x2f)からなること。
修正UTF-7の仕様は以下となります。
アンパサンド(0x26)以外の印字可能文字が含まれること。
上記1以外の文字はアンパサンド(0x26)とハイフン(0x2d)の間にBase64でエンコードされていること。アンパサンド(0x26)とハイフン(0x2d)が連続した場合はデコードした際にアンパサンド(0x26)になります。
上記2でいうところのBase64エンコードされた文字は数字(0x30から0x39)、英大文字(0x41から0x5a)、英小文字(0x61から0x7a)、プラス(0x2b)、カンマ(0x0c)からなること。
この仕様で検知してしまえばいいと。あとはASCIIを優先的に検知するためにBase64を開始終了する記号(UTF-7ならプラス(0x2b)とハイフン(0x2d)、修正UTF-7ならアンパサンド(0x26)とハイフン(0x2d))に挟まれている部分がなければ、ASCIIであるとします。
ここまでできたら次のステップに移ります。次に何をやるかは次の記事で。