Project Description
Ve Parser is an implementation of Combinatory Parser concept in .Net environment using C# language. It allows to very easily write parsers for your language by writing its grammar using your favorite .Net language. Not only it does parse the input, but also it generates a decent output.

Update

Just released the new version, in order to have some improvements I forced to change some names or functionalities that may affect your parsers(if you have written using version 1.0). Lets me know if you have any problem in migrating your existing parser to use this new version.

Nuget

To add a reference to Ve Parser in your project:
PM> Install-Package veparser

Introuduction

Like other combinatory parsers, we used functional structures available in .Net and specially High Order Functions in order to design Ve Parser; however, the functions, which are used in the Ve parser, have a different structure in comparison with others; and consequently, a number of remarkable merits are provided. For instance, this parser is by far the simplest and easiest to understand among other combinatory parsers and it has the possibility of parallel processing for choice combinators. On the other hand, the usage of object-oriented approaches will lead to avoid of restrictions of pure functional programming. Moreover, Ve Parser has the ability of generating Abstract Syntax Tree in an integrated way and the output of parsing will be a concrete conceptual object.

What is a Combinatory Parser How Ve Parser works?

The only jargon I used in the project and even in the source codes are 'Combinator Parser' and 'Lexer'. I dont want to make it more complex by explaining what a combinator parser is, but if you are curious you can see its page in wiki pedia. You see, its a little complicated subject but Ve Parser is much simpler that the name 'combinatory parser' suggests. So instead of describing what is a Combinatory Parser I will describe how Ve Parser works:
Ve Parser is defined only a delegate type named Parser which has no input and has a boolean output. Parser is a delegate type, so variables of type Parser are functions that can be executed, when a Parser executes it returns a boolean value. The result value from a Parser specifies if it was successful for or not.
Then there is ParserBase class which is an abstract class you have to derive from. When you derive from it you have to implement the abstract method -GetRootParser-. To implement this GetRootParser the BaseParser class provided you with a set of functions which all of them get inputs of type Parser and produce a Parser as result, as long as all of them have the output type of Parser and all of them have input of type Parser they can used combined toghether to form a more mature parser from a more basic parser and finaly make a root parser. For example it would look like 'seq(oneOrMore(....),any(...),seq(any(zeroOrMore(...))))'. Here the seq function is being called by passing the result of oneOrMore parser, any and seq. Then seq parser returns a parser as result.

Features

  • Simple to use. Simple to learn. Although hard to understand how it works internally.
  • No dependency on any grammar language, only pure C# code can be used to design and implement a parser.
  • Rich grammar authoring preset. The ParserBase is shiped with a whole bunch of useful parser combinators like : seq, any, zeroOrMore, zeroOrOne, oneOrMore, zeroOrMoreAny, zeroOeMoreSeq, oneOrMoreAny, oneOrMoreSeq and deleimitedList and mixture.
  • Producing output result from the parsed content. (A.k.a Abstract Syntax Tree generation).
  • Extensible. Although there are lots of useful combinators you can wrote your own combinators to the library. I am looking to hearing from you about any new combinator that you may suggest.
  • Probably fast, if you wrote a neat grammar it should be fast. I need to evaluate performance more percisely to claim about it speed.
  • Grammar debugging. Yes that's it, you can monitor the executation of the parser, and also you can put breakpoints in your parser code to see how it is performing. (_Although this features require some improvements, so the next version would be even better).
  • Shiped with a default Lexer.
  • Lightweight library, with no dependency to any other library. Just you need .Net 4 to use it. And itself is only a couple of essential classes and some other helper classes.

Sample Code

Probably a good way to describe the library is a sample code of how a Parser using Ve Parser would look like:
Here is a small part of a sample CSV parser that parse a simple CSV content and result a list of rows which each row is list of values:
Note: This code is based on the latest source codes (downloadable through Source Code tab) and it would not work with the current released version.
    public class CSVParser : BaseParser<char>
    {
        public const char comma = ',';
        public const char newline = '\n';

        protected override Parser GetRootParser()
        {
            var seperatorParser = toParser(ch => ch == comma);
            var lineBreakParser = seq(toParser(ch => ch == '\r'), toParser(ch => ch == '\n'));
            var itemParser = createNewText(zeroOrMore(appendText(keep(toParser(ch => ch != comma && ch != '\n' && char.IsLetterOrDigit(ch))))));
            var lineParser = createNewList(deleimitedList(seperatorParser, add(itemParser)));
            var fileParser = createNewList(deleimitedList(lineBreakParser, add(lineParser)));
            return seq(fileParser, endOfFile());
        }
    }

And below is the code which describes how the above parser will be used:

[TestMethod]
public void CSVParserTest()
{
    var csvContent = @"column1,column2
19,20";
    var csvParser = new CSVParser();
    dynamic result = csvParser.Parse(csvContent.ToCharArray());
    Assert.IsNotNull(result);
    Assert.AreEqual(result.Count, 2);
    foreach (var row in result)
    {
        Assert.AreEqual(row.Count, 2);
    }
    Assert.AreEqual(result[0][0], "column1");
    Assert.AreEqual(result[0][1], "column2");
    Assert.AreEqual(result[1][0], "19");
    Assert.AreEqual(result[1][1], "20");
}

Last edited Dec 1, 2011 at 1:15 PM by MeysamNaseri, version 12