簡體   English   中英

C# 解析 IF-ELSE 語句

[英]C# Parse IF-ELSE Statement

更新

我不希望您為我做我的工作並為我編寫代碼,我只是想朝正確的方向發展!

所以我必須更具體地解決我的問題,給我一個機會在這方面做一些工作,我會用結果更新我的問題;-)

更新 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"
   }
}

有人可以給我一個正確方向的推動嗎?

如果您使用Roslyn進行語法重寫。 不僅僅是寫你能做什么,這里有一個簡單的例子。

基本上它是如何工作的。 你為你的代碼創建一個語法樹,然后使用預定義的訪問者來訪問你想要重寫的那些節點,你用有效的 C# 代碼替換它們,然后你可以編譯這個樹並使其工作。

編輯:

另一個更可靠的來源,有一個例子

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM