I'm working with a service that provides data as a Lisp-like S-Expression string. This data is arriving thick and fast, and I want to churn through it as quickly as possible, ideally directly on the byte stream (it's only single-byte characters) without any backtracking. These strings can be quite lengthy and I don't want the GC churn of allocating a string for the whole message.
My current implementation uses CoCo/R with a grammar, but it has a few problems. Due to the backtracking, it assigns the whole stream to a string. It's also a bit fiddly for users of my code to change if they have to. I'd rather have a pure C# solution. CoCo/R also does not allow for the reuse of parser/scanner objects, so I have to recreate them for each message.
Conceptually the data stream can be thought of as a sequence of S-Expressions:
(item 1 apple)(item 2 banana)(item 3 chainsaw)
Parsing this sequence would create three objects. The type of each object can be determined by the first value in the list, in the above case "item". The schema/grammar of the incoming stream is well known.
Before I start coding I'd like to know if there are libraries out there that do this already. I'm sure I'm not the first person to have this problem.
EDIT
Here's a little more detail on what I want as I think the original question may have been a little vague.
Given some SExpressions, such as:
(Hear 12.3 HelloWorld)
(HJ LAJ1 -0.42)
(FRP lf (pos 2.3 1.7 0.4))
I want a list of objects equivalent to this:
{
new HearPerceptorState(12.3, "HelloWorld"),
new HingeJointState("LAJ1", -0.42),
new ForceResistancePerceptorState("lf", new Polar(2.3, 1.7, 0.4))
}
The actual data set I'm working on is a list of perceptors from a robot model in the RoboCup 3D simulated soccer league. I may potentially also need to deserialise another set of related data with a more complex structure.
I wrote an S-Expression parser in C# using OMeta#. It can parse the kind of S-Expressions that you are giving in your examples, you just need to add decimal numbers to the parser.
The code is available as SExpression.NET on github and a related article is available here. As an alternative I suggest to take a look at the YaYAML YAML parser for .NET also written using OMeta#.
Here's a relatively simple (and hopefully, easy to extend) solution:
Testable here:
https://repl.it/CnLC/1
'HTH,
Consider using Ragel. It's a state machine compiler and produces reasonably fast code.
It may not be apparent from the home page, but Ragel does have C# support. Here's a trivial example of how to use it in C#
Look at gplex and gppg.
Alternatively, you can trivially translate the S-expressions to XML and let .NET do the rest.
In my opinion a parse generator is unneccessary to parse simple S-expressions consisting only of lists, numbers and symbols. A hand-written recursive descent parser is probably simpler and at least as fast. The general pattern would look like this (in java, c# should be very similar):
Drew, perhaps you should add some context to the question, otherwise this answer will make no sense to other users, but try this:
Oh, I have to point out that
'\u0020'
is the unicode SPACE, which you are subsequently removing with "- ' '
". Oh, and you can useCONTEXT (')')
if you don't need more than one character lookahead.FWIW:
CONTEXT
does not consume the enclosed sequence, you must still consume it in your production.EDIT:
Ok, this seems to work. Really, I mean it this time :)