1

更新

我不想让你做我的工作并为我编写代码,我只是想要一个正确的方向!

所以我必须更具体地处理我的问题,给我一个机会做一些工作,我会用结果更新我的问题;-)

更新 2

我已经用 Roslyn 解决了我的问题,可能不是很优雅,但它可以满足我的需要,这里是代码 ;-)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;

namespace ParserTest
{
    public class MyParser
    {
        private int _currentLevel = 1;

        public void TestMethod()
        {
            string testString =
            @"  if(@ISEMPTY(temp.tis_filterstatus2))
                {
                    tis_datasheet_selection.is_selected = 'Y'
                }
                else
                {
                    if(@ISEMPTY(temp.tis_programmtyp_filter)) { }
                    else
                    {
                         AND tis_programme_v.type = '@SUB(temp.tis_programmtyp_filter)'
                    }
                    if(@ISEMPTY(temp.tis_programmfilter)) { }
                    else
                    {
                         AND tis_programme_v.programm LIKE '@SUB(temp.tis_programmfilter)%'
                    }";

            var result = this.Parse(testString);
            var finalResult = this.GenerateDsl(result);
        }

        public List<IfStatement> Parse(string strToParse)
        {
            var result = new List<IfStatement>();
            var syntaxTree = SyntaxTree.ParseText(@"using System;class C{static void M(){" + strToParse + "}}");

            var rootNodes = syntaxTree.GetRoot().DescendantNodes().Where(getRootNodes);

            result = rootNodes.Select(n => ToIfStatement(n, null)).ToList();
            ApplyNestingLevel(result);

            return result;
        }

        private string GenerateDsl(List<IfStatement> list)
        {
            var sb = new StringBuilder();

            foreach(var ifStmt in list)
            {
                IfStatementToDsl(ifStmt, sb);
            }
            return sb.ToString();
        }

        private string IfStatementToDsl(IfStatement ifStmt, StringBuilder sb)
        {
            string sqr = "";
            for (int i = 0; i < ifStmt.Level; i++)
            {
                sqr += "'";
            }

            sb.Append("@IF(");
            sb.Append(ifStmt.Condition.ApplyLevel(ifStmt.Level) + "," + sqr);
            sb.Append(ifStmt.Statement.ApplyLevel(ifStmt.Level));
            if(ifStmt.Childs.Count > 0)
            {
                foreach(var c in ifStmt.Childs)
                {
                    IfStatementToDsl(c, sb);
                }
            }
            sb.Append(sqr + "," + sqr);
            if(ifStmt.Else != null)
            {
                sb.Append(ifStmt.Else.Statement.ApplyLevel(ifStmt.Level));

                foreach(var c in ifStmt.Else.Childs)
                {
                    IfStatementToDsl(c, sb);
                }
            }
            sb.Append(sqr + ")");
            return sb.ToString();
        }

        #region Parsing-Methods

        private IfStatement ToIfStatement(SyntaxNode node, SyntaxNode parent)
        {
            var ifNode = (IfStatementSyntax)node;

            var ifStmt = new IfStatement
            {
                Condition = ifNode.Condition.ToString(),
                Statement = GetIfStatement(ifNode),
                Childs = GetIfChilds(ifNode)
            };
            if (ifNode.Else != null)
            {
                ifStmt.Else = new ElseStatement
                {
                    Statement = GetElseStatement(ifNode.Else),
                    Childs = GetElseChilds(ifNode.Else)
                };
            }
            return ifStmt;
        }

        private List<IfStatement> GetIfChilds(IfStatementSyntax node)
        {
            var childs = node.Statement.DescendantNodes().Where(n => WhereIfNodes(n, node));
            return childs.Select(n => ToIfStatement(n, node)).ToList();
        }

        private List<IfStatement> GetElseChilds(ElseClauseSyntax node)
        {
            var childs = node.Statement.DescendantNodes().Where(n => WhereElseNodes(n, node));
            return childs.Select(n => ToIfStatement(n, node)).ToList();
        }

        private string GetIfStatement(IfStatementSyntax node)
        {
            var result = node.Statement.DescendantNodes().Where(n => WhereIfStatement(n, node));
            string returnValue = "";
            foreach (var n in result)
            {
                returnValue += n.ToString();
            }
            return returnValue.CleanString();
        }

        private string GetElseStatement(ElseClauseSyntax node)
        {
            var result = node.Statement.DescendantNodes().Where(n => WhereElseStatement(n, node));
            string returnValue = "";
            foreach (var n in result)
            {
                returnValue += n.ToString() + " ";
            }
            return returnValue.CleanString();
        }

        private void ApplyNestingLevel(List<IfStatement> list)
        {
            foreach (var item in list)
            {
                item.Level = _currentLevel;
                if (item.Childs.Count > 0 || (item.Else != null && item.Else.Childs.Count > 0))
                {
                    _currentLevel++;
                }
                ApplyNestingLevel(item.Childs);
                if (item.Else != null)
                {
                    ApplyNestingLevel(item.Else.Childs);
                }
            }
        }

        #endregion

        #region Linq Where-Conditions

        private bool WhereIfNodes(SyntaxNode node, IfStatementSyntax parent)
        {
            if(node.Kind == SyntaxKind.IfStatement && (node.Parent.Parent == parent))
            {
                return true;
            }
            return false;
        }

        private bool WhereElseNodes(SyntaxNode node, ElseClauseSyntax parent)
        {
            if (node.Kind == SyntaxKind.IfStatement && (node.Parent.Parent == parent))
            {
                return true;
            }
            return false;
        }

        private bool WhereIfStatement(SyntaxNode node, IfStatementSyntax parent)
        {
            if ((node.Kind == SyntaxKind.ExpressionStatement || node.Kind == SyntaxKind.LocalDeclarationStatement) 
                && (node.Parent.Parent == parent))
            {
                return true;
            }
            return false;
        }

        private bool WhereElseStatement(SyntaxNode node, ElseClauseSyntax parent)
        {
            if ((node.Kind == SyntaxKind.ExpressionStatement || node.Kind == SyntaxKind.LocalDeclarationStatement) 
                && (node.Parent.Parent == parent))
            {
                return true;
            }
            return false;
        }

        private Func<SyntaxNode, bool> getRootNodes =
            n => n.Kind == SyntaxKind.IfStatement &&
                (n.Parent.Parent.Kind != SyntaxKind.ElseClause && n.Parent.Parent.Kind != SyntaxKind.IfStatement);

        #endregion
    }

    public class IfStatement
    {
        public int Level { get; set; }

        public string Condition { get; set; }

        public string Statement { get; set; }

        public ElseStatement Else { get; set; }

        public List<IfStatement> Childs { get; set; }
    }

    public class ElseStatement
    {
        public string Statement { get; set; }

        public List<IfStatement> Childs { get; set; }
    }

    public static class Ext
    {
        public static string CleanString(this string value)
        {
            return value.Replace("\t", "").Replace("\n", "").Replace("\r", "");
        }

        public static string ApplyLevel(this string value, int level)
        {
            int multiplier = level * 2;
            if (level == 0) 
                multiplier = 1;
            var sb = new StringBuilder(multiplier);
            for (int i = 0; i < multiplier; i++)
            {
                sb.Append("'");
            }
            return value.Replace("'", sb.ToString());
        }
    }
}

我必须用特定领域的语言编写 if-else 语句,这真是令人头疼!

(DSL 来自第三方工具,我必须使用它来为 SQL 查询生成 WHERE 语句)

句法:

@IF(@ISEMPTY(@SUB(temp.last_name))),'if true','else')

@SUB() 读取一个文本框值

样本:

@IF(@ISEMPTY(@SUB(temp.last_name))),'','account_contact.last_name = ''DOE'' ')

你必须在 else 语句中加倍你的单引号,如果你想在每次更深层次时嵌套不同的“if-else”,你必须加倍加倍的单引号!

如果你有复杂的条件,你会发现写起来不是很简单......

所以我想我写了一个解析器,将一个普通的 if-else 语句转换成这个 DSL 语法!

解析器应该创建这个类的对象:

public class IfCondition
{
    public int ID { get; set; }

    public int ParentID { get; set; }

    public int Level { get; set; }

    public string Condition { get; set; }

    public string Content { get; set; }

    public string ElseContent { get; set; }
}

基于这些对象的集合,我可以生成 DSL 语句!

所以我的问题是我真的不知道如何解析这样的字符串:

IF(@ISEMPTY(@SUB(temp.last_name))) { } 
ELSE
{
   IF(@SUB(temp.test) = 'Y')
   {
       account_contact.last_name = 'DOE'
   }
   ELSE
   {
       account_contat.first_name = "JOHN"
   }
}

有人可以在正确的方向上轻推我吗?

4

1 回答 1

1

如果您使用Roslyn进行语法重写。不只是写你能做什么,这里有一个简单的例子。

基本上它是如何工作的。您为您的代码创建一个语法树,然后使用预定义的访问者访问您想要重写的那些节点,将它们替换为有效的 C# 代码,然后您可以编译此树并使其工作。

编辑:

另一个更可靠的来源,有一个例子

于 2013-11-08T12:14:14.770 回答