日本語トランスコンパイラ言語 Re:Mind（リマインド）の試作バージョンを日本語ロジック仕様記述言語 Re:Mindで内部設計する（ターゲット言語Mind）

# はじめに
2023年の1月下旬よりQiita様へ参加させていただき、[自作言語 Re:Mind（リマインド）の企画趣旨をQiita内の記事](https://qiita.com/mylifewithviolin/items/9d58db8a101807c19bde)でご説明させていただいております。まだ実装がなにもないので、そろそろ試作に着手しようかと考えております。

本記事はその試作品の内部設計情報で、ターゲット言語をMindとしています。

## この記事内容の作業目的
試作にあたって内部構想を、[日本語ロジック仕様記述言語 Re:Mind](https://qiita.com/mylifewithviolin/items/52f806777e6ea031de94)で記述しておきます。本試作範囲は策定仕様のごくごく一部です。ターゲット言語は一部のみ対応、言語の対応ソース構文も超限定的です。


## この記事内容の保証
※この記事には仕様的な情報が含まれます。自作言語はまだ設計開発中のため、発案者による実装は存在しません。本記事に開示された仕様は次バージョンの仕様においては予告なく変更される場合があります。また、このバージョンの仕様内で補足や追加がなされる場合があります。


# 補足
日本語ロジック仕様記述言語 Re:Mind（リマインド）は[オープンな設計言語仕様](https://qiita.com/mylifewithviolin/items/52f806777e6ea031de94)で、どなたでもこの記法を使いロジックを記述することができます。
日本語トランスコンパイラ言語 Re:Mind（リマインド）は[オープンな実装言語仕様](https://qiita.com/mylifewithviolin/items/9a6abbab62c0f5e27d4b)で、どなたでもコンパイラ・トランスコンパイラを実装することができます。

# 試作概要・試作目的
本試作では日本語トランスコンパイラ言語 Re:Mind（リマインド）の原型を検証し、いろいろな問題点を洗い出します。ターゲット言語のソースコード入力は実装言語のソースコードのインライン記述にとどまります。試作範囲は段階的に拡張してまいります。

## 本試作の設計言語
・ロジック仕様記述言語 Re:Mind

## 本試作の実装言語
・C#
コンソールアプリケーションとして実装します。

## 本試作のターゲット言語
本試作のターゲット言語としては下記の3言語を想定しております、本記事はそのうちのMindに該当する内容です。
・C#
・Java
・**Mind**　　　←本記事(仕様)の対象言語

・想定稼働OS Windows

## 本試作のターゲット言語の対応仕様範囲
"Hello World!"がコンソール出力されるソースコードを入力して（インライン・リテラルコーディング）、ターゲット言語のソースコードを（双方だらだらと）コンソール出力する。（どちらを出力するかは起動パラメータにする。）

### お題のターゲット言語出力ソースコード
#### Mind
```mind:main.src
    メインとは
        「Hello World!」を　一行表示する。

```
### お題のトランスコンパイラ言語 Re:Mind入力ソースコード(ターゲット言語依存)
#### Mind
当初、下記のようなソースコードを想定しておりましたが、（インラインソース機能風）
```mind:Re:Mind
    ▽メイン
       □コンソールへ一行表示する("Hello World!")
    △
    ▽コンソールへ一行表示する(string value)
       □一行表示する(string value)
    △

```
下記のように引用定義としてMind予約語の「一行表示する」を定義するに訂正しました。Mind予約語の再定義記法としてはあまりにもC言語風の記法に寄ってしまっていますが、現時点ではこちらで暫定対応とします。
```mind:Re:Mind
    ▽メイン
       □コンソールへ一行表示する("Hello World!")
    △
    ▼コンソールへ一行表示する(string value)
       ■一行表示する(string value)
    ▲

```
## 本試作の内部設計の妥当性
試作のため本実装には採用されない可能性があります。また、試作品の実装段階でフィードバック訂正される場合があります。

# クラス構成
お手数ですが[内部設計（基本構成）](https://qiita.com/mylifewithviolin/items/0ecfbfbaafcce6645d82)をご参照ください。

# クラス・メンバの構成
お手数ですが[内部設計（基本構成）](https://qiita.com/mylifewithviolin/items/0ecfbfbaafcce6645d82)をご参照ください。

# クラスTargetMind

ターゲット言語Mindのトークナイザとコードジェネレータを保持するクラスの実装です。
## 列挙体、クラス(変数のみ)の宣言

お手数ですが[内部設計（基本構成）](https://qiita.com/mylifewithviolin/items/0ecfbfbaafcce6645d82)をご参照ください。

## SubMain
クラスProgramのメイン関数から、コンソールアプリケーションの起動パラメータで"mind"が指定されたときに実行されるサブメイン関数です。（クラスTargetMindの実質メイン関数）
クラスTargetCsのサブメイン関数との差異は、リスト型 ユージングリストがないことです。

```mind:Re:Mind
    /**
    * SubMain
    * @param ソース soruce
    */
    ▽static サブメイン(string ソース)

        ・int 戻り値 = 0
        ・リスト型<ソース行型> ソース行リスト =リスト型<ソース行型>で初期化
        ・リスト型<ターゲットソース行型> ターゲットソース行リスト =リスト型<ターゲットソース行型>で初期化
        ・辞書型 名称辞書  = 辞書型<string, string>で初期化
        
        □名称辞書を初期化する(名称辞書)
        □戻り値= ノードカテゴライズする(ソース,ソース行リスト)
        ◇戻り値!=0 の場合
            □コンソール.一行表示( "ノードカテゴライズに失敗しました。")
            □戻り値を　返す
        ◇ここまで

        □戻り値= 名称辞書を収集する(ソース行リスト,名称辞書)
        ◇戻り値!=0 の場合
            □コンソール.一行表示( "名称辞書の収集に失敗しました。")
            □戻り値を　返す
        ◇ここまで

        □戻り値= トランスコンパイルする(ソース行リスト,ターゲットソース行リスト,名称辞書)
        ◇戻り値!=0 の場合
            □コンソール.一行表示( "トランスコンパイルに失敗しました。")
            □戻り値を　返す
        ◇ここまで
        
        □コード出力する(ターゲットソース行リスト,ソース行リスト)
        □戻り値を　返す

    △
```

## SubMainから直接呼ばれる主要関数
### 名称辞書を初期化する
この処理は今回の試作では不要ですが、将来的にMindの予約語とRe:Mindの予約語を対応づけるために用意しておきます。
```mind:Re:Mind
    /**
    * initNameDictionary
    * @param 名称辞書 nameDictionary
    */
    ▽static 名称辞書を初期化する(辞書型<string, string> 名称辞書)
    △
```

### ノードカテゴライズする
第１引数の「ソース」はRe:Mind（リマインド）のソースコード文字列全体です。「ソース」を改行で分割して、各ソース行の先頭文字「ノード」でソース行をカテゴライズした第2引数「ソース行リスト」に格納します。

```mind:Re:Mind
    /**
    * nodeCategorized
    * @param ソース source
    * @param ソース行リスト sourcesLineList
    */
    ▽static int ノードカテゴライズする(string ソース,リスト型<ソース行型> ソース行リスト)
        ・int 戻り値 = 1
        □ライン文字列配列 = ソース.Split("\r\n")
        〇i=0,i<ライン文字列配列.Length,i++ 繰り返す
                ・ソース行 =new ソース行型
                ・ソース行文字列=ライン文字列配列[i]
                □ソース行.ソース行番号=i+1
                □ソース行.オリジナルソース文字列=ソース行文字列
                □ソース行文字列=ソース行文字列.Trim()
                □ソース行.オリジナルインデント=ソース行.オリジナルソース文字列.Substring(0,ソース行.オリジナルソース文字列.Length-ソース行文字列.Length)
                □ソース行.ノード種類=ソース行ノードを判定する(ref ソース行文字列)//ノード種類を判定する
                ◇ソース行.ノード種類==ノード種類.例外　の場合
                    コンソール.一行表示する(ソース行.オリジナルソース文字列)               
                    □戻り値を　返す
                ◇ここまで 
                □ソース行.行文字列=ソース行文字列
                □ソース行リスト.追加(ソース行)

        〇ここまで

        □ret=0//ここまで進行したら成功
        □戻り値を　返す
    △
```


### トランスコンパイルする
第１引数の「ソース行リスト」はノードカテゴライズするでカテゴライズされたソース行型のリストで、これをもう一度分析して、第3引数の名称辞書を使ってターゲット言語Mindの単語に置換してから、第2引数のターゲットソース行型のリストを返します。



### コード出力する
ターゲットソース行リストを出力しますが、ソース行リストから元のインデントを復元しています。ユージングリストの事前出力はいまのところありません。

```mind:Re:Mind
    /**
    * codeOutput
    * @param ターゲットソース行リスト targetSourcesLineList
    * @param ソース行リスト sourcesLineList
    */
    ▽static コード出力するする(リスト型<ターゲットソース行型> ターゲットソース行リスト,リスト型<ソース行型> ソース行リスト)
        〇i=0,i<ターゲットソース行リスト.Count,i++ 繰り返す
             ・ターゲットソース =ターゲットソース行リスト.ElementAt(i)
             □コンソール.表示する(オリジナルのインデントを取得する(ソース行リスト,ターゲットソース.ソー0ス行番号))
             □コンソール.一行表示する(ターゲットソース.ターゲット行文字列)
        〇ここまで
    △
```

### 支援関数
#### ノードカテゴライズする から呼ばれる支援関数
##### ソース行ノードを判定する
ソース行のノードを判定して、ノード種類列挙体の特定値を返します。


この関数のC#をターゲットとしたクラスTargetCsとの差異はありません。詳細はお手数ですが[内部設計（ターゲット言語C#）](https://qiita.com/mylifewithviolin/items/a0754013787a513828a4)をご参照ください。

#### トランスコンパイルする から呼ばれる支援関数
##### ターゲットソース行を生成する
```mind:Re:Mind
    /**
    * generateTargetSouceLine
    * @param ソース行 sourceLines
    * @param ターゲットソース行リスト targetSourcesLineList
    * @param ノード種類 nodeKind
    * @param 名称辞書 nameDictionary
    * @param ターゲットソース行番号 targetSouceLineNumber
    */
    ▽static int ターゲットソース行を生成する(ソース行型 ソース行,リスト型<ターゲットソース行型> ターゲットソース行リスト,ノード種類列挙体 ノード種類,辞書型<string, string> 名称辞書,ref int ターゲットソース行番号)
        ・int 戻り値 = 1
        ・ターゲットソース行 =new ターゲットソース行型
        ・ソース行文字列=ソース行.行文字列 ?? ""  
        ◇ノード種類　で分岐する
        ◇ノード種類列挙体.定義開始//定義開始
            □ターゲットソース行番号+=1
            □ターゲットソース行.ソース行番号=ソース行.ソース行番号
            □ターゲットソース行.ターゲット行文字列=名称辞書でターゲットソース行を置換する(名称辞書,ソース行文字列)+"とは"//名称辞書で置換する+"とは"
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行リスト.追加(ターゲットソース行)
            □脱出する
        ◇ノード種類列挙体.定義終了//定義終了
            □脱出する
        ◇ノード種類列挙体.引用定義終了//引用定義終了
            □脱出する
        ◇ノード種類列挙体.宣言開始//宣言開始
        ◇ノード種類列挙体.実行開始//実行開始
            □ターゲットソース行番号+=1
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行.ターゲット行文字列=名称辞書でターゲットソース行を置換する(名称辞書,ソース行文字列)+"。"//名称辞書で置換し実行文終端+"。"を追加
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行リスト.追加(ターゲットソース行)
            □脱出する
        ◇ノード種類列挙体.引用定義開始//引用定義開始
            □脱出する
        ◇ノード種類列挙体.単行備考開始//単行備考開始
            □ターゲットソース行番号+=1
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行.ターゲット行文字列=ソース行.行文字列.置換(ソース行のノード種類.単行備考開始,ターゲットソース行のノード種類.単行備考開始)
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行リスト.追加(ターゲットソース行)
            □脱出する
        ◇ノード種類列挙体.JavaDoc備考開始//JavaDoc備考開始
            □ターゲットソース行番号+=1
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行.ターゲット行文字列=ソース行.行文字列.置換(ソース行のノード種類.JavaDoc備考開始,ターゲットソース行のノード種類.JavaDoc備考開始)
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行リスト.追加(ターゲットソース行)
            □脱出する
        ◇ノード種類列挙体.JavaDoc備考途中//JavaDoc備考途中
            □ターゲットソース行番号+=1
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行.ターゲット行文字列= ソース行.行文字列.置換(ソース行のノード種類.JavaDoc備考途中,ターゲットソース行のノード種類.JavaDoc備考途中)
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行リスト.追加(ターゲットソース行)
            □脱出する
        ◇ノード種類列挙体.JavaDoc備考変数//JavaDoc備考変数
            □ターゲットソース行番号+=1
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行.ターゲット行文字列= ソース行.行文字列.置換(ソース行のノード種類.JavaDoc備考変数,ターゲットソース行のノード種類.JavaDoc備考変数)
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行リスト.追加(ターゲットソース行)
            □脱出する
        ◇ノード種類列挙体.JavaDoc備考終了//JavaDoc備考終了
            □ターゲットソース行番号+=1
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行.ターゲット行文字列=ソース行.行文字列.置換(ソース行のノード種類.JavaDoc備考終了,ターゲットソース行のノード種類.JavaDoc備考終了)
            □ターゲットソース行.ターゲットソース行番号=ターゲットソース行番号
            □ターゲットソース行リスト.追加(ターゲットソース行)
            □脱出する
        //行レベルカテゴライズ済のため例外は生じない
        ◇ここまで
        □ret=0//ここまで進行したら成功
        □戻り値を　返す
    △
```
##### 名称辞書でターゲットソース行を置換する
支援関数のC#をターゲットとしたクラスTargetCsとの差異はありません。詳細はお手数ですが[内部設計（ターゲット言語C#）](https://qiita.com/mylifewithviolin/items/a0754013787a513828a4)をご参照ください。

##### 引数ブロックを置換する
Mindの引数の語順を置換する処理です。

```mind:Re:Mind
    /**
    * nameDictionaryReplase
    * @param 名称辞書 nameDictionary
    * @param ソース行文字列 sourceLineString
    */
    ▽static string 引数ブロックを置換する(string ソース行文字列)
         ・temp引数ブロック=""
         ・tempソース=""
         ・pos=ソース行文字列.IndexOf(ソース行のノード種類.引数開始)
          ◇pos>0　の場合//かっこが出現した場合
                tempソース=ソース行文字列.置換(ソース行文字列.Substring(pos),"").Trim()//かっこ開始から右側は除去
                temp引数ブロック=ソース行文字列.Substring(pos);
                temp引数ブロック=temp引数ブロック.置換(ソース行のノード種類.引数開始,"").置換(ソース行のノード種類.引数終了,"")
                temp引数ブロック="「"+temp引数ブロック.置換("\"","")+"」を"
                ソース行文字列=temp引数ブロック+" "+tempソース
        ◇ここまで
       □ソース行文字列を　返す
    △
```

# 参考リンク

https://qiita.com/mylifewithviolin/items/9a6abbab62c0f5e27d4b

https://qiita.com/mylifewithviolin/items/52f806777e6ea031de94

https://qiita.com/mylifewithviolin/items/ebb406bf5ea7a4eea24c