简体   繁体   中英

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

I´ve solved my Problem with Roslyn maybe not very elegant but it work for my needs, here is the code ;-)

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!

(The DSL is from a Third-Party-Tool which I have to use to generate WHERE-Statements for SQL-Queries)

Syntax:

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

@SUB() reads a textboxvalue

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!

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!

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!

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. 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.

EDIT:

Another, more reliable source with an example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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