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?

ParserScript 3.0の概要

Last updated at Posted at 2024-11-02

現在、ParserScriptは非推奨です。

ParserScriptはバージョン2.0から大きく分けて新たに3つ(実質2つ)のコマンドが追加されました。

CSREGEXコマンド

 このコマンドには3つ機能があります。と言っても、実質2つだけです。

CSREGEX MATCHコマンド

 例: 以下のコードは、実数にマッチするようになっています。

CSREGEX MATCH "((-)?[0-9]+(\.[0-9]+)?)"

 これは見ての通りパースする文字列の先頭からマッチングを行います。

CSREGEX ISMATCHコマンド

 例: 以下のコードは、パースする文字列の先頭がaまたはbの時、「OK」と出力するコードです。

CSREGEX ISMATCH "(a|b)"
    STRING
    PUSH "... OK."
END

 これも見ての通り、パースする文字列の先頭がISMATCHの正規表現にマッチしたらそのままコードを実行し、マッチしなかったら対応するENDに飛びます。

CSREGEX ISNOMATCH

 名前の通りISMATCHの逆です。

ISSTART?, ISNOSTART?コマンド

 例: 以下のコードはパースする文字列の先頭がaなら「OK」、それ以外なら、「aではない」と出力するコードです。

PUSH "\""
ISSTART? "a"
    STRING
    PUSH "\""
    PUSH " is OK."
END
ISNOSTART? ""
    STRING
    PUSH "\""
    PUSH " isn't \"a\""
END

 これも見ての通りですね。え、ISNOSTART?の文字列は"a"じゃないのかって?
 いえいえ、これが正しいのです。説明しましょう。
 まず、ISNOSTART?の時に残る文字列は"(a以外の文字)..."か、""かです。ISSTART?にマッチしなかったら文字列を喰わずに、マッチしたら全て喰うからです。ここでISSTART?では喰えなかった文字列を喰うために、""にして"(a以外の文字)..."を喰うようにします。だからISNOSTART? ""と書くのです。

その他追加された機能

コマンドの解釈

 ParserScriptは以前まで

MATCH " "

PUSH " "

などと書くと

MATCH, ", "
PUSH, ", "

と解釈されていました。
しかし、以下のC#のコード

internal static class Converter
{
    public static string[] Split2(this string s, string split) => [.. Regex.Split(s.EndsWith(split) ? s : s + split, @$"("".*""{split}|[^{split[0]}]*{split})").Where(x => x != "").Select(x => string.Join("", x.SkipLast(split.Length)))];
}

のSplit2メソッドを使って先のParserScriptのコードを

MATCH, " "
PUSH, " "

と解釈するようになりました。

エスケープ文字対応

 ParserScriptは以前までエスケープ文字をReplaceメソッドで書き換えていたのですが、それだとReplaceメソッドの置く場所を変えたら、例えば"\\n"を\と改行文字が並んだものや\とnが並んだものと解釈されます。実際、バージョン2.0までは"\\n"を\と改行文字が並んだものと解釈していました。この問題をバージョン3.0では先ほどのConverterクラスに

public static string Replace(this string s) => string.Join("", Replace().Replace(string.Join("", s[(int.TryParse("0", out int i) ? 0 : 0)..]), "$1").Aggregate(Array.Empty<string>(), (x, y) => [.. x.Append(s[i].ToString() is "\\" ? s[i++].ToString() + s[i++].ToString() : s[i++].ToString())]).Select(x => x is "\\n" ? "\n" : (x is "\\t" ? "\t" : (x is "\\s" ? " " : (x is "\\\\" ? "\\" : (x is "\\\"" ? "\"" : x))))));

[GeneratedRegex(@"(\\).")]
private static partial Regex Replace();

を追加することで解決しました。これは

a\\nb\\sc\\td\\\\e\\"f(エスケープで\を表した時)

a, \\n, b, \\s, c, \\t, d, \\\\, e, \\", f

と解釈し、

a, \n, b, \s, c, \t, d, \\, e, \", f

に変換した後、連結して

a\nb\sc\td\\e\"f

にします。
結果は

a
b c    d\e"f

になります。

終わりに

 ParserScriptはバージョン3.0になってC#の正規表現を使えるようになり、一応あの長いコードを短くできますが条件分岐やブロックの終わりを示すENDとLASTの数が条件分岐のコマンドとASTの数と違っても許されるので、それを許さないものをバージョン3.1に実装しようと思います。

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?