MikoScript 言語仕様

 文字列リテラル

文字列リテラル(定文字列)は、文字列型の一定のデータを表します。
文字列リテラルには、以下の3形態の表記があります。
    ・通常文字列
    ・純粋文字列
    ・直記文字列

●通常文字列
通常文字列は、下例のように、対象の文字列を二重引用符( " )で囲って表します。
    "This is a 通常文字列."
通常文字列は、1行内に記述する必要があります。つまり、二重引用符の囲い中には、
直接、改行コードを入れることはできません。通常文字列内に、改行コードを入れるには、
エスケープ文字の \n を使います。たとえば、
    print   "1行目\n2行目\n3行目";
を実行すると、
    1行目
    2行目
    3行目
とプリントされます。

エスケープ文字は、各種の制御コードや特別の文字等を表記する場合に使います。
エスケープ文字の表記は、\ で始まり、次にアルファベット1字が続きます。
この2字で1つの特定の文字コードを表します。
また、任意の値の文字コードを表したい場合は、\x に続けて1〜2桁の16進の数字を
書きます。たとえば、\x7F はコード値が 0x7F の文字を表し、\x6 はコード値が 0x06 
の文字を表します。
いずれの表記でも、1つのエスケープ文字は、1バイト(8ビット)のコードを表わしま
す。ちなみに、全角文字は2バイトなので、エスケープ文字が2つ必要です。たとえば、
"あ" は、"\x82\xA0" となります。
エスケープ文字の8進表記は、現バージョンでは、扱っていません。

エスケープ文字の一覧表を以下に示します。
   表記      値     意味
    \a      0x07    ベル
    \b      0x08    バックスペース
    \e      0x1B    エスケープ
    \f      0x0C    改頁(フォームフィード)
    \n      0x0D    改行(ラインフィード)
    \r      0x0A    復帰(キャリッジリターン)
    \t      0x09    水平タブ
    \v      0x0B    垂直タブ
    \0      0x00    ヌル
    \xNN    NN が16進数で表す値

エスケープ文字の \ の次の文字が上表にある文字以外の場合、その文字自身を表します。
この原則によって、\ は \\ として表わせます。また、" は \" として表わせます。
たとえば、
    print   "二重引用符内の \" と \\ は、\\\" と \\\\ として表わせます";
を実行すると、
    二重引用符内の " と \ は、\" と \\ として表わせます
とプリントされます。

エスケープ文字を使うのは、3種の文字列リテラルのうち、通常文字列だけです。

なお、\ 直後に改行コードがある場合、その \ と改行コードは、その文字列には含まれ
ずに、その次の行の先頭からがその続きになります。文字列が長い場合に、この表記を使
うこともできますが、普通は、後述の連続表記を使います。

●純粋文字列
純粋文字列は、下例のように、$ に続けて対象の文字列を二重引用符で囲って表します。
    $"This is a 純粋文字列."
純粋文字列では、二重引用符の囲い中に、エスケープ文字は使えません。従って、\ は 
1字で \ 自身を表します。これは、 \ を常用する正規表現やファイルのパスを表記する
時に便利です。たとえば、ブロックコメントに一致する正規表現は、
    純粋文字列の場合:  $"#m/\*(.|\n)*\*/"
    通常文字列の場合:  "#m/\\*(.|\\n)*\\*/"
となります。( なお、#m は最小一致を指令するモードです )

また、純粋文字列は、通常文字列と同様に、1行内に記述する必要があります。この制約
は、囲い内の文字列が長くなる場合に、不便なようですが、後述の連続表記を使うと、特
に支障なく書けます。また、この表記ではコメントを添えることができます。たとえば、
    $"(\s+)|"           //  空白
    $"([-+]?\d+)|"      //  整数
    $"(\a[\a\d]*)"      //  変数名
と書いたものは、
    $"(\s+)|([-+]?\d+)|(\a[\a\d]*)"
と1つにまとめて書いたものと同じです。

純粋文字列では、囲い内の文字列に、囲い文字を含めることはできません。そのため、囲
い文字は、" だけでなく、'  `  /  %  !  も使えるようになっています。たとえば、囲
い文字として / を使うと、以下のように、" を対象の文字列内に含めることができます。
    $/("ABC"|"XYZ")/
どの囲い文字を使う場合でも、囲いの開始文字と終了文字は同じ文字になります。
上例では、囲いの開始に / を使っているので、囲いの終了も / になります。

●直記文字列
直記文字列は、対象の文字列を ## と ## で囲って表します。
この囲いの中は、改行やタブのような特殊なコードでも、エスケープ表記なしに、
そのまま含むことができます。そのため、複数行に渡るような長い文字列も
見た目通りに記述できます。たとえば、
##
  これは直記文字列です。
  この表記は長文にも便利です。
##
という直記文字列(  はタブを示す)は、通常文字列では、
  "\n\tこれは直記文字列です。\n\tこの表記は長文に便利です。\n"
となります。

直記文字列では、囲い内の文字列に、囲い文字を含めることはできません。そのため、囲
い文字は、## だけでなく、#"  #'  #`  #/  #%  #! も使えます。
たとえば、囲い文字として #' を使うと、以下のように、## を対象の文字列内に含める
ことができます。
    #'直記文字列内に ## の包含は可能です。#'
どの囲い文字を使う場合でも、囲いの開始文字と終了文字は同じ文字になります。
上例では、囲いの開始に #' を使っているので、囲いの終了も #' になります。

後述の連続表記は、直記文字列の場合でも可能です。また、別の表記形態の文字列との
混在も可能です。たとえば、
    ##abc##  ##いろは##  "XYZ"  $"123"
は、
    "abcいろはXYZ123"
と同じです。

さらに重要なことは、直記文字列の中には、スクリプト式、マクロ、コメントが
書けることです。

スクリプト式は、直記文字列の中に、 ${ スクリプト式 } という形態で入ります。
    ##計算結果は ${ ( x + 1 ) * ( y - 1 ) } です。##
直記文字列の中のスクリプト式は、その直記文字列の文が実行される時に評価されて、
その評価値に対応する文字列が、${ ... } 部と置き換わります。たとえば、
    a = 8;
    b = 9;
    print ##さて、${a} と ${b} を足すと ${ a + b } になります##;
を、実行すると、
    さて、8 と 9 を足すと 17 になります
とプリントされます。また、
    v = 123;
    s = ##変数 v の16進値は 0x${ v'x(4) } です##;
    print s;
を、実行すると、
    変数 v の16進値は 0x007b です
とプリントされます。

ここで、注意すべきことは、${ ... } 内に書けるのは、スクリプト式だということです。
スクリプト式は、変数、定数、演算式、関数コールなどで、文法的に、( と ) の丸括弧
で囲えるものです。したがって、${ ... } 内には、if 文や for 文等のスクリプト文は
書けません。また、空も不可で、関数定義なども書けません。

直記文字列内で、$ が特別な意味を持つのは、${ ... } の場合だけで、
$ の次に来る文字が、{ でなければ、通常の文字と同様に扱われます。

マクロは、通常文字列内や純粋文字列内では認識されませんが、直記文字列内では
有効です。たとえば、
    #set    M   マクロ展開文字列
    print   ##これは、#M です##;    // 直記文字列内ではマクロは有効
    print   "これは、#M です";      // 通常文字列内ではマクロは無効
を実行すると、
    これは、マクロ展開文字列 です
    これは、#M です
とプリントされます。なお、直記文字列内でも、展開対象のマクロの名前は、
識別名のトークンとして認識されるように記述されている必要があります。
例えば、上例で、
    print   ##これは、#Mです##;
とすると、マクロ名が、「M」ではなく「Mです」になってしまいます。
「#M」と「です」の間に半角空白を入れているのはそのためです。この空白を
入れたくない時は、例えば、次のようにします。
    print   ##これは、#M#--#です##;
ここで使っている #- と -# は、コメントです(詳細後述)。

次に、直記文字列内の ${ ... } 部でマクロを使った例を示します。
    #set    Age( a, b )     ${ #a }の体力年齢は ${ #b - 5 } 才です
    x = 25;
    print   #`#Age( "太郎", x )#`;
を実行すると、
    太郎の体力年齢は 20 才です
とプリントされます。

通常のコメントは、文字列内では、無効ですが、直記文字列内では、以下の範囲が、
直記文字列内専用のコメント部になります。
    ・#- から -# まで
    ・#- から改行コードまで
このコメント部は、プログラムの翻訳時に単に読み飛ばされるだけで、直記文字列には
含まれません。たとえば、
    print
    ##
    ここから、#- 直記文字列内専用のコメント -# です。
    ここから、#- 直記文字列内専用のコメント
    改行コードまでがコメントです。
    /* 通常のコメント */ は、無効です。
    ##;
を実行すると、
    ここから、 です。
    ここから、改行コードまでがコメントです。
    /* 通常のコメント */ は、無効です。
とプリントされます。
なお、#- から行末までのコメントの場合、改行コードはコメントに含まれるので、
その行は次行に改行なしで連結されることになります。

直記文字列の中で、# 自身を表わすには、\# とします。
また、$ 自身を表わすには、\$ とします。

直記文字列の中で、\ の次が改行コードの場合、つまり、\ が行末にある場合、
その \ と改行コードは、プログラムの翻訳時に読み飛ばされて、
その直記文字列のデータには含まれません。

直記文字列の中の \ は、以上の場合を除いて、つまり、
\ の次が  #  $  改行コード  以外の場合、特別な意味はなく、\ 自身になります。

直記文字列は、内部的には、${ スクリプト式 } で区切られます。
この各区切り間に書ける文字列の字数は、半角文字単位(全角文字は半角文字2個に相当)
で、最大 65535 字までという制限があります。たとえば、
    ##<文字列部1>${...}<文字列部2>${...}<文字列部3>##
のような場合、<文字列部1>, <文字列部2>, <文字列部3> に書ける字数は、
それぞれ、最大 65535 字までです。
なお、${ スクリプト式 } が生成する文字列の長さには、制限はありません。

●文字列リテラルの連続表記
文字列リテラルは、どの表記形態の文字列でも、空白を挿んで連続する場合、
文法的には、1つの定文字列として扱われます。
たとえば、"ABC" "xyz" は、"ABCxyz" と書くのと同じです。
また、"111" "222" "333" は、"111222333" と書くのと同じです。
さらに、改行やコメントを挿んだ以下のような表記も可能です。
    "文字列(1)\n"    // 注釈(1)
    "文字列(2)\n"    // 注釈(2)
    "文字列(3)\n"    // 注釈(3)
この場合、
    "文字列(1)\n文字列(2)\n文字列(3)\n"
と書くのと同じです。

●まとめ
ここで、各文字列表記形態のまとめと補足事項を掲載します。

     通常文字列    純粋文字列    直記文字列  
囲い文字 "..." $"..." (*1)##...## (*2)
表記例 "ABCいろは" $"(A|B)\d+" ##A=${X+Y}##
\エスケープ 有効 無効 (*3) 無効
#マクロ 無効 無効 有効
${スクリプト式} 無効 無効 有効
#-コメント-# 無効 無効 有効
連続表記
" の表記 \" 不可 (*4) "
\ の表記 \\ \ \ (*5)
$ の表記 $ $ $ (*6)
# の表記 # # \# (*7)
改行直前の \ (*8)行連結 \ 自身 行連結
強制終端 (*9) NUL,CR,LF,EOF NUL,CR,LF,EOF EOF
記述可能行範囲 1行内 1行内 多行
最大字数 (*10) 65535字 65535字 65535字/区間
(*1) $ の次の記号は " ' ` / % ! が選択できるので、以下の囲いも可能 $'...'  $`...`  $/.../  $%...%  $!...! (*2) # の次の記号は " ' ` / % ! が選択できるので、以下の表記も可能 #"...#"  #'...#'  #`...#`  #/...#/  #%...#%  #!...#! (*3) ここでの「\エスケープ」は、文字列表記に関するもので、 正規表現での「\エスケープ」とは無関係。 (*4) 囲いが $"..." 場合、その中に " を含めるのは不可。 囲いがそれ以外(例えば「$/.../」)の場合は、" をそのまま記述可。 (*5) 直記文字列内では、\ の次の文字が、# $ 改行コード以外の場合に、 \ はそのまま記述可。 (*6) 直記文字列内では、$ の次の文字が、{ 以外の場合に、$ はそのまま記述可。 (*7) 直記文字列内では、# の次が、マクロ識別名、囲い文字、専用コメント以外なら、 # は通常文字扱いになりますが、直記文字列内で # 自身を表わす場合は、 慣習上、一律に \# と書くようにする方が良いでしょう。 (*8) 通常文字列と直記文字列では、改行直前に \ があれば、\ と改行コードを 含めないで、その行は次行に連結されます。 (*9) 文字列は、囲いの終りがなくても、表中の文字コードまたは条件に遭遇した場合、 強制的に終了します。表中の記号の意味は以下の通り。 NUL,CR,LF: それぞれ、0x00,0x0D,0x0A の値の ASCII コード EOF: ファイル終端 (*10) 連続表記の場合でも、その総計字数が、この最大字数を超えられません。 ●注意事項 ・本言語の文字列は、あくまで文字列型のデータであって、C言語のように、  文字の配列になるわけではありません。 ・文字列を文字の配列として扱いたい場合は、純粋配列を使います。詳細は、以下参照。    ・純粋配列の要素データ上の文字コード列の操作 ・\0 を含む文字列には注意が必要です。\0 は、通常、文字列の終端として扱います。  このため、たとえば、 print "abc\0xyz";  を実行しても、 abc  としかプリントされません。