简体   繁体   English

C# 解析 IF-ELSE 语句

[英]C# Parse IF-ELSE Statement

UPDATE更新

I don´t want you to do my Work and write code for me I just wanted a nurge in the right Direction!我不希望您为我做我的工作并为我编写代码,我只是想朝正确的方向发展!

So I have to be more specific with my Problem, give me a chance to do some work on this and I will update my question with the results ;-)所以我必须更具体地解决我的问题,给我一个机会在这方面做一些工作,我会用结果更新我的问题;-)

UPDATE 2更新 2

I´ve solved my Problem with Roslyn maybe not very elegant but it work for my needs, here is the code ;-)我已经用 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());
        }
    }
}

I have to write if-else Statements in a Domain-Specific-Language which is really a pain in the ass!我必须用特定于领域的语言编写 if-else 语句,这真是太麻烦了!

(The DSL is from a Third-Party-Tool which I have to use to generate WHERE-Statements for SQL-Queries) (DSL 来自第三方工具,我必须使用它来为 SQL 查询生成 WHERE 语句)

Syntax:语法:

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

@SUB() reads a textboxvalue @SUB() 读取文本框值

Sample:样品:

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

you have to double your single-quotes in the else statement and if you want to nest different "if-else" every time you go a level deeper you have to double the doubled single-quotes!您必须将 else 语句中的单引号加倍,并且如果您想在每次深入时嵌套不同的“if-else”,则必须将加倍的单引号加倍!

You see it´s not very simple to write if you have complicated contitions...你看,如果你有复杂的条件,写起来不是很简单......

So I thought I write a parser that transforms a normal if-else statement to this DSL-Syntax!所以我想我写了一个解析器,将普通的 if-else 语句转换为这个 DSL 语法!

The Parser should create objects of this class:解析器应该创建这个类的对象:

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; }
}

based on a Collection of this Objects I could generate the DSL-Statements!基于此对象的集合,我可以生成 DSL 语句!

So my Problem is I really don´t have a clue, how to parse a String like this:所以我的问题是我真的不知道如何解析这样的字符串:

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

can somebody give me a nudge in the right direction?有人可以给我一个正确方向的推动吗?

If you use Roslyn for syntax rewritting.如果您使用Roslyn进行语法重写。 Not to just write about what you can do, here is an easy example.不仅仅是写你能做什么,这里有一个简单的例子。

Basically how it works.基本上它是如何工作的。 You create a syntax tree for your code and then use predefined visitors to visit those nodes you want to rewrite, you replace them by valid C# code and then you can compile this tree and make it work.你为你的代码创建一个语法树,然后使用预定义的访问者来访问你想要重写的那些节点,你用有效的 C# 代码替换它们,然后你可以编译这个树并使其工作。

EDIT:编辑:

Another, more reliable source with an example另一个更可靠的来源,有一个例子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM