LoginSignup
1
1

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

Last updated at Posted at 2023-07-19

はじめに

2023年の1月下旬よりQiita様へ参加させていただき、自作言語 Re:Mind(リマインド)の企画趣旨をQiita内の記事でご説明させていただいております。まだ実装がなにもないので、そろそろ試作に着手しようかと考えております。本記事はその試作品の内部設計情報で、ターゲット言語をMindとしています。

この記事内容の作業目的

試作にあたって内部構想を、日本語ロジック仕様記述言語 Re:Mindで記述しておきます。本試作範囲は策定仕様のごくごく一部です。ターゲット言語は一部のみ対応、言語の対応ソース構文も超限定的です。

この記事内容の保証

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

補足

日本語ロジック仕様記述言語 Re:Mind(リマインド)はオープンな設計言語仕様で、どなたでもこの記法を使いロジックを記述することができます。
日本語トランスコンパイラ言語 Re:Mind(リマインド)はオープンな実装言語仕様で、どなたでもコンパイラ・トランスコンパイラを実装することができます。

試作概要・試作目的

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

本試作の設計言語

・ロジック仕様記述言語 Re:Mind

本試作の実装言語

・C#
コンソールアプリケーションとして実装します。

本試作のターゲット言語

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

・想定稼働OS Windows

本試作のターゲット言語の対応仕様範囲

"Hello World!"がコンソール出力されるソースコードを入力して(インライン・リテラルコーディング)、ターゲット言語のソースコードを(双方だらだらと)コンソール出力する。(どちらを出力するかは起動パラメータにする。)

お題のターゲット言語出力ソースコード

Mind

main.src
    メインとは
        「Hello World!」を 一行表示する。

お題のトランスコンパイラ言語 Re:Mind入力ソースコード(ターゲット言語依存)

Mind

当初、下記のようなソースコードを想定しておりましたが、(インラインソース機能風)

Re:Mind
    ▽メイン
       □コンソールへ一行表示する("Hello World!")
    △
    ▽コンソールへ一行表示する(string value)
       □一行表示する(string value)
    △

下記のように引用定義としてMind予約語の「一行表示する」を定義するに訂正しました。Mind予約語の再定義記法としてはあまりにもC言語風の記法に寄ってしまっていますが、現時点ではこちらで暫定対応とします。

Re:Mind
    ▽メイン
       □コンソールへ一行表示する("Hello World!")
    △
    ▼コンソールへ一行表示する(string value)
       ■一行表示する(string value)
    ▲

本試作の内部設計の妥当性

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

クラス構成

お手数ですが内部設計(基本構成)をご参照ください。

クラス・メンバの構成

お手数ですが内部設計(基本構成)をご参照ください。

クラスTargetMind

ターゲット言語Mindのトークナイザとコードジェネレータを保持するクラスの実装です。

列挙体、クラス(変数のみ)の宣言

お手数ですが内部設計(基本構成)をご参照ください。

SubMain

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

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

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

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

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

    △

SubMainから直接呼ばれる主要関数

名称辞書を初期化する

この処理は今回の試作では不要ですが、将来的にMindの予約語とRe:Mindの予約語を対応づけるために用意しておきます。

Re:Mind
    /**
    * initNameDictionary
    * @param 名称辞書 nameDictionary
    */
    ▽static 名称辞書を初期化する(辞書型<string, string> 名称辞書)
    △

ノードカテゴライズする

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

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//ここまで進行したら成功
        □戻り値を 返す
    △

トランスコンパイルする

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

コード出力する

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

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

支援関数

ノードカテゴライズする から呼ばれる支援関数

ソース行ノードを判定する

ソース行のノードを判定して、ノード種類列挙体の特定値を返します。

この関数のC#をターゲットとしたクラスTargetCsとの差異はありません。詳細はお手数ですが内部設計(ターゲット言語C#)をご参照ください。

トランスコンパイルする から呼ばれる支援関数

ターゲットソース行を生成する
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#)をご参照ください。

引数ブロックを置換する

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ソース
        ◇ここまで
       □ソース行文字列を 返す
    △

参考リンク

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1