エレファント・ビジュアライザー調査記録

ビジュアルプログラミングで数式の変形を表すことを考えていくブロクです。

自由モノイドのイテレーター(12)

自由モノイドプログラミング言語の作成(MonIter C#版 バージョン1.1)

C# のコードを生成するために構文の要素を変更します。C# の関数の定義ではパラメーターに型を指定しなければならないのでその部分を変更します。全体の構文は同じです。

以前 C# のコードを実行する方法がないと書きましたが、「Roslyn for Scripting」というものを使えばできるようです。まだできていませんのでできたら公開したいと思います。

構文解析のコードは「拡張メソッド」を使うと少しまとめることができるようです。

拡張メソッドのクラス

以下のようなクラスを作ると「拡張メソッド」を使うことができます。

    internal static class ParserExtension
    {
        public static Parser<T> ParenEnclosed<T>(this Parser<T> parser)
        {
            return parser.Contained(Parse.Char('(').Token(), Parse.Char(')').Token());
        }
        public static Parser<IEnumerable<T>> ListBy<T>(this Parser<T> parser, char sep)
        {
            return parser.DelimitedBy(Parse.Char(sep).Token());
        }
    }

構文解析のクラス

「拡張メソッド」を使って書き直します。

    internal class MonParser
    {
        private static readonly Parser<Expression> ParseExpression =
            Parse.Ref(() => ParseExpression_);

        private static readonly Parser<Number> ParseNumber =
            from num in Parse.Decimal.Token()
            select DomainExpression.Number(num);

        private static readonly Parser<Identifier> ParseIdentifier =
            from name in Parse.Identifier(Parse.Letter, Parse.LetterOrDigit.Or(Parse.Char('_'))).Token()
            select DomainExpression.Identifier(name);

        private static readonly Parser<ParameterName> ParseParameterName =
            from name in Parse.Identifier(Parse.Letter, Parse.LetterOrDigit.Or(Parse.Char('_'))).Token()
            select Expression.ParameterName(name);

        private static readonly Parser<DomainTerm> ParseDomainTerm =
            ((Parser<DomainTerm>)ParseIdentifier).Or(ParseNumber);

        private static readonly Parser<DomainExpression> ParseDomainExpression =
            from list in ParseDomainTerm.ListBy('+')
            select new DomainExpression(list);

        private static readonly Parser<IEnumerable<DomainExpression>> ParseDomainExpressionList =
            ParseDomainExpression.ListBy(',');

        private static readonly Parser<DomainFunction> ParseDomainFunction =
            from name in ParseIdentifier
            from list in ParseDomainExpressionList.ParenEnclosed()
            select Expression.DomainFunction(name, list);

        private static readonly Parser<IEnumerable<Expression>> ParseExpressionList =
            ParseExpression.ListBy(',');

        private static readonly Parser<Function> ParseFunction =
            from pr in Parse.Char('$').Token()
            from name in ParseIdentifier
            from list in ParseExpressionList.ParenEnclosed()
            select Expression.Function(name, list);

        private static readonly Parser<Term> ParseTerm =
            ((Parser<Term>)ParseFunction).Or(ParseDomainFunction).Or(ParseDomainExpression);

        private static readonly Parser<Expression> ParseExpression_ =
            from list in ParseTerm.ListBy('&')
            select new Expression(list);

        private static readonly Parser<Statement> ParseExpressionStatement =
            from exp in ParseExpression
            select Statement.ExpressionStatement(exp);

        private static readonly Parser<IEnumerable<ParameterName>> ParseParameterList =
            ParseParameterName.ListBy(',');

        private static readonly Parser<Definition> ParseDefinition =
            from pr in Parse.String("def").Token()
            from name in ParseIdentifier
            from list in ParseParameterList.ParenEnclosed()
            from eq in Parse.Char('=').Token()
            from exp in ParseExpression
            select Statement.Definition(name, list, exp);

        private static readonly Parser<Statement> ParseStatement =
            ParseDefinition.Or(ParseExpressionStatement);

        private static readonly Parser<Prog> ParseProgram =
            from list in ParseStatement.ListBy(';')
            select new Prog(list);

        public static Prog ParseProg(string src) { return ParseProgram.Parse(src); }
    }