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

Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

{
    "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();
    }
}


Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

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

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}