自由モノイドプログラミング言語の作成(MonIter バージョン1.2 仕様(23))
C# 構文木の調査
「自由モノイドのイテレーター(16) - エレファント・ビジュアライザー調査記録」に書いた構文木を調べる方法についてまとめます。
C# 構文木の調査用のクラス
/// <summary> /// C# 構文木の調査のためのクラス /// </summary> internal class CSStyleTreeScan { /// <summary> /// C# 構文木の調査の結果 /// </summary> private string result = ""; /// <summary> /// C# 構文木の調査の結果 /// </summary> public string Result { get => result; set => result = value; } /// <summary> /// 調査結果を追加する /// </summary> /// <param name="text">追加するテキスト</param> private void WriteLine(string text) { result += text + "\r\n"; } /// <summary> /// C# の構文木のノードを調べる /// </summary> /// <param name="node">C# の構文木のノード</param> /// <param name="n">階層の数</param> private void ScanSyntax(CSharpSyntaxNode node, int n) { string spc = " " + string.Concat(Enumerable.Repeat("- ", n).ToArray()); WriteLine($"{spc}構文要素 {node.Kind()}"); WriteLine($"{spc} {node.ToFullString()}"); WriteLine($"{spc} 型 {node.GetType().Name}"); if (node is LocalFunctionStatementSyntax localFunctionStatement) { WriteLine($"{spc} 文字列 Identifier.Text: {localFunctionStatement.Identifier.Text}"); } else if (node is IdentifierNameSyntax identifierName) { WriteLine($"{spc} 文字列 Identifier.Text: {identifierName.Identifier.Text}"); } else if (node is ParameterSyntax parameter) { WriteLine($"{spc} 文字列 Identifier.Text: {parameter.Identifier.Text}"); } else if (node is LiteralExpressionSyntax literalExpression) { WriteLine($"{spc} 文字列 Token.Text: {literalExpression.Token.Text}"); } else if (node is PredefinedTypeSyntax predefinedType) { WriteLine($"{spc} 文字列 Keyword.Text: {predefinedType.Keyword.Text}"); } WriteLine($"{spc} 下位の要素数 {node.ChildNodes().Count()}"); foreach (var child in node.ChildNodes()) { if (child is CSharpSyntaxNode syntax_node) { ScanSyntax(syntax_node, n + 1); } } } /// <summary> /// C# のコードの文字列から構文解析して構文木を調べる /// </summary> /// <param name="src">C# のコードの文字列</param> public void ScanSource(string src) { var tree = CSharpSyntaxTree.ParseText(src); var root = tree.GetCompilationUnitRoot(); foreach (var child in root.Members) { ScanSyntax(child, 0); } } }
調査したい構文木のノードをこのクラスに追加していきます。
例:引数で渡すバージョン
C# スタイルのコード
mon fib(int x, int y) => x & fib(y, x + y); fib(0, 1)
を構文解析して C# の構文木を調べるには以下のようにします。
/// <summary> /// フィボナッチ数列 C# スタイルのコードの構文解析の結果を調べる(引数あり) /// </summary> /// <returns>構文解析の結果</returns> private string InfiniteFibpnacciPrmsCSStyleTreeScan() { string src = "mon fib(int x, int y) => x & fib(y, x + y); fib(0, 1)"; CSStyleTreeScan scanner = new CSStyleTreeScan(); scanner.ScanSource(src); return scanner.Result; }
例:Zip を使うバージョン
C# スタイルのコード
mon fib(int x, int y) => x & y & zipsum(fib(x, y), tail(fib(x, y)); fib(0, 1)
を構文解析して C# の構文木を調べるには以下のようにします。
/// <summary> /// フィボナッチ数列 C# スタイルのコードの構文解析の結果を調べる(Zip) /// </summary> /// <returns>構文解析の結果</returns> private string InfiniteFibpnacciZipCSStyleTreeScan() { string src = "mon fib(int x, int y) => x & y & zipsum(fib(x, y), tail(fib(x, y)); fib(0, 1)"; CSStyleTreeScan scanner = new CSStyleTreeScan(); scanner.ScanSource(src); return scanner.Result; }





