0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ChainCC, DepthCC開発中

Last updated at Posted at 2025-03-17

 今回は自作DSLのChainCC (Chain type Compiler Creation script)のほとんどの処理が完成したので、紹介しようと思います。

開発経緯

 前に作った言語 (ParserScript (非推奨), UCCScript) と関係があるので、それらを踏まえて書きます。

ParserScript

強いところ

・コマンドベースだから簡単
・処理中に別の処理を書ける

弱いところ

・コードを書く難易度が高め
・演算できない
・保守性低い
・時々、バグる
・読みづらい

UCCScript

強いところ

・BNF風に書ける
・制御構文がある
・演算ができる
・使いたい文字列を参照できる

弱いところ

・実装が難しい
・仕様上のバグがある
・まだ読みづらい

 二つの言語には上のような長所と短所があります。なので、ChainCCの開発目標としては

・コマンドベースで簡単
・ある程度の制御構文なら簡単に再現できる
・演算ができる
・使いたい文字列を参照できる
・バグなし
・まあまあ読みやすい

です。

どう解決したのか

 開発途中というのもあって、大体完成しています。

ある程度の制御構文なら簡単に再現できる

ParserScript, UCCScript:「コードの先が分からない、、、」

 ParserScriptとUCCScriptは与えられた文字しかわかりません。「〜または〜」とか「〜に0回以上マッチ」の実装が複雑なのです。

ChainCC:「コマンドをまとめとけば良くね?(以下、このことを「グループ」と呼ぶ)」

if not match
    .after match "\("
    .after call Expr
    .after match "\)"
loop
    .after match "a"

 ChainCCは.afterでコマンドをまとめられます。その間はコマンドは実行されずに読み込まれ、終端に来ると今まで読み込んだコマンドを実行します。

使いたい文字列を参照できる

UCCScript:「私は囲まれたパターンにマッチした文字列を参照できるのよ」

ParserScript:「そのせいで、処理は複雑になったし、仕様上のバグも発生したよね」

UCCScript:「...」

 実際、繰り返し中に配列の参照を二つ以上使うと、動作は問題ないが、バグることが確認されています。

ChainCC:「配列の参照はなくして、繰り返しの最後で削除すれば?」

loop
    .after (
        ref R0
            .after match "a"
    )
    .after if <R0>
    .after push <R0>
    .after result last
    .after delete R0

 現在の仕様上、R0のパターンにマッチしなければ自動的にR0は消されるため、条件分岐が必要。
 
 ParserScriptの「処理中に別の処理を書ける」を利用したものです。UCCScriptとは違い、配列に保存しなくても、その場で処理できます。

まあまあ読みやすい

 ParserScriptはとにかく分かりづらいコマンドが多すぎるので、作者 (私)自身もう忘れたので、UCCScriptとChainCCの比較をします。

 以下は文字を逆向きにするコード
UCCScript

Grammar.ucc
First Sample End
$Sample In { <{ Char }> }
        Is (Load Index[$0+[0] 1 -])
           (ForB[0 \Index > !][
               @1[0 \Index]
               (Load Index[\Index 1 -])
            ]) 
        End

ChainCC

Grammar.ccc
first Sample

label Sample
    loop
        .after (
            ref R0
                .after match "."
        )
        .after if <R0>
        .after push <R0>
        .after result first
        .after delete R0
end

圧倒的にChainCCの方が読みやすいですよね。

lock, unlock (予定)

 グループの最初につけるタイプ。lockを使い、その後に続くグループを次回から、コマンド実行毎に実行する。firstまたはlastをつけて、いつ実行するのかを決める。
 unlockfirstまたはlastを付け、開放する

逆ポーランド記法に変換するコードを書いてみる

ChainCC

Grammar.ccc
trim ' '
first Expression

label Factor
    ref R0
        .after match ""(-)?[0-9]+(\.[0-9]+)?""
    if not match
        .after if ""\(""
        .after match ""\(""
        .after (
            ref R0
                .after call Expression
                
        )
        .after match ""\)""
    if <R0>
        .after push <R0>
    if not <R0>
        .after push """"
    result last
end

label Term
    ref R0
        .after call Factor
    push ?<R0>
    ope rev
    gotob CCC_0001
    push <R0>
    result last
    #CCC_0000
    if not ""(\*|/)""
        .after goto CCC_0001
    ref R1
        .after match ""(\*|/)""
    ref R2
        .after call Factor
    if <R1>
        .after if <R2>
        .after push "" ""
        .after result last
        .after push <R2>
        .after result last
        .after push "" ""
        .after result last
        .after push <R1>
        .after result last
    if <R1>
        .after delete R1
    if <R2>
        .after delete R2
    goto CCC_0000
    #CCC_0001
end

label Expression
    ref R0
        .after call Term
    push ?<R0>
    ope rev
    gotob CCC_0001
    push <R0>
    result last
    #CCC_0000
    if not ""(\+|-)""
        .after goto CCC_0001
    ref R1
        .after match ""(\+|-)""
    ref R2
        .after call Term
    if <R1>
        .after if <R2>
        .after push "" ""
        .after result last
        .after push <R2>
        .after result last
        .after push "" ""
        .after result last
        .after push <R1>
        .after result last
    if <R1>
        .after delete R1
    if <R2>
        .after delete R2
    goto CCC_0000
    #CCC_0001
end

--追記
FactorExpressionまではいいですがTermを使うとエラーが発生しました。呼び出しの深さにも対応させる予定です

--追記の追記
・オーバーフローしていたので、gotoコマンド、gotobコマンド(条件gotoコマンド)を導入して、呼ばれる関数の数を減らして、対応しました。
 

終わりに

 現在、ChainCCにはラベルの機能などがないので、そこを実装して完成です。

--追記
・バグがまだたくさんありますが、公開しました(ChainCC-Ver.0.0)。
・バグ修正とともに機能も追加して対応しています。

--追記の追記
・完成版を公開しました(ChainCC-Ver.1.0)。

--追記の追記の追記
・ChainCC 1.0の修正版:ChainCC-Ver.2.0

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?