Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Create a Simple Parser in C# With Sprache

DZone's Guide to

Create a Simple Parser in C# With Sprache

If you need something more powerful than RegEx, but you don't quite need ANTLR, Sprache could be a happy middle ground for parsing that you can incorporate in your code.

· Web Dev Zone
Free Resource

Discover how to focus on operators for Reactive Programming and how they are essential to react to data in your application.  Brought to you in partnership with Wakanda

{
    "projects": [
        "src",
        "test"
    ]
}


"dependencies": {
    "Sprache": "2.1.0"
},


 "dependencies": {
    "System.Runtime.Serialization.Primitives": "4.3.0",
    "xunit": "2.1.0",
    "dotnet-test-xunit": "1.0.0-rc2-192208-24",
    "SpracheGame": {
      "target": "project"
    }
},


 "runtimes": {
        "win7-x64": {},
        "win8-x64": {},
        "win81-x64": {},
        "win10-x64": {}
    }


public class GameParser
{
    public static Parser<string> Number = Parse.Digit.AtLeastOnce().Text().Token();

    public static Parser<Command> Command = Parse.Char('<').Then(_ => Parse.Char('>'))
                                                .Return(SpracheGameCore.Command.Between)
                                            .Or(Parse.Char('<')
                                                .Return(SpracheGameCore.Command.Less))
                                            .Or(Parse.Char('>')
                                                .Return(SpracheGameCore.Command.Greater))
                                            .Or(Parse.Char('=')
                                                .Return(SpracheGameCore.Command.Equal));


    public static Parser<Play> Play =
        (from action in Command
        from value in Number
        select new Play(action, value, null))
    .Or(from firstValue in Number
        from action in Command
        from secondValue in Number
        select new Play(action, firstValue, secondValue));
}


public class Play
{
    readonly Command _command;
    readonly int _firstNumber;
    readonly int _secondNumber;

    public Play(Command command, string firstNumber, string secondNumber)
    {
        _command = command;

        if (!int.TryParse(firstNumber, out _firstNumber))
            throw new ArgumentNullException("firstNumber");

        if (secondNumber != null)
        {
            if (!int.TryParse(secondNumber, out _secondNumber))
                throw new ArgumentNullException("secondNumber");
        }
    }

    public Command Command { get { return _command; } }

    public int FirstNumber { get { return _firstNumber; } }

    public int SecondNumber { get { return _secondNumber; } }

    public bool Evaluate(int number)
    {
        bool result = false;

        switch (Command)
        {
            case Command.Greater:
                result = number > FirstNumber;
                break;

            case Command.Less:
                result = number < FirstNumber;
                break;

            case Command.Between:
                result = (number > FirstNumber) && (number < SecondNumber);
                break;

            case Command.Equal:
                result = number == FirstNumber;
                break;
        }

        return result;
    }
}


public class GameParserTests
{
    [Theory]
    [InlineData("1")]
    [InlineData("10")]
    [InlineData("100")]
    public void CanParseNumbers(string value)
    {
        var number = GameParser.Number.Parse(value);

        Assert.Equal(number, value);
    }

    [Fact]
    public void CanParseGreaterCommand()
    {
        Command command = GameParser.Command.Parse(">");

        Assert.Equal(command, Command.Greater);
    }

    [...]

    [Fact]
    public void FailParseWrongPlay()
    {            
        Assert.Throws<ParseException>(() => GameParser.Play.Parse("> Number"));
    }
}


static void Main(string[] args)
{
    Random rand = new Random();
    int numberToGuess = rand.Next(1, 100);
    bool finished = false;

    Console.WriteLine("******************************************************");
    Console.WriteLine("*                                                    *");
    Console.WriteLine("* Guess the number by asking questions               *");
    Console.WriteLine("* Use < X to ask if the number is less than X        *");
    Console.WriteLine("* Use > X to ask if the number is greater than X     *");
    Console.WriteLine("* Use X <> Y to ask if the number is between X and Y *");
    Console.WriteLine("* Use = X to guess the number                        *");
    Console.WriteLine("* Use q to quit                                      *");
    Console.WriteLine("*                                                    *");
    Console.WriteLine("******************************************************");

    while (!finished)
    {
        try
        {
            var input = Console.ReadLine();
            if (input.Trim() == "q")
                finished = true;
            else
            {
                Play play = GameParser.Play.Parse(input);
                bool result = play.Evaluate(numberToGuess);
                Console.WriteLine(result);

                if (play.Command == Command.Equal && result == true)
                {
                    Console.WriteLine("You guessed right.");
                    finished = true;
                }
            }
        }
        catch (ParseException ex)
        {
            Console.WriteLine("There was an error: {0}", ex.Message);
        }

        Console.WriteLine();
    }
}


Learn how divergent branches can appear in your repository and how to better understand why they are called “branches".  Brought to you in partnership with Wakanda

Topics:
c# ,sprache ,web dev ,tutorial ,parsing

Published at DZone with permission of Federico Tomassetti, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}