1

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?

4
  • 6
    Generally speaking, if you want to be thorough, you should define a grammar and then write a lexer/parser using a framework such as Irony or Antlr, etc. That said, have you considered an ORM such as Entity Framework? IMO, it's much easier for users to write code in C# than in some made-up language. Commented Nov 8, 2013 at 12:07
  • 4
    While it may be an interesting question, it is in its current format not suited for Stack Overflow (so, note to to the upvoters, that is not how upvotes work here). You're basically asking us to analyze your problem and write the code to solve it. If you don't have a clue how to write such a parser, try at programmers.stackexchange.com. Commented Nov 8, 2013 at 12:09
  • I assume your parser has no concept of sql-parameters, has it? That looks as if it could be a sql-injection utility. Commented Nov 8, 2013 at 12:11
  • The DSL is from an Third-Party which unfortunately I HAVE TO use, I have to write Queries in there "DEV-Studio"! Commented Nov 8, 2013 at 12:28

1 Answer 1

0

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

Sign up to request clarification or add additional context in comments.

5 Comments

I could also provide some code sample once I'm home from an office.
Sorry, I don't know if I downvoted by error, so I upvoted again..hmm..I'll better go reading on how to use SO properly :)
thanks Ondrej would be nice to have some sample code to start with!
@sine Definitely check out the second link. It is directly from MSDN blogs and these guys can provide some nice samples. I will provide a sample as well so that the answer is complete and does not have to rely on external sources ;)
looks exactly what I was looking for, thanks I will accept you answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.