MEPS

MEPS is a parser combinator written for Squeak Smalltalk. MEPS consists of an interface used to build parsers, plus a set of method extensions in PositionableStream which combine the parsers. MEPS has been used for everything from one-liners to complete Java parsers. MEPS also includes a regular expression parser implemented in itself. MEPS can be downloaded here or from SqueakMap.

Examples:

ledger
ruby

Here is a very simple parse using MEPS:

'f' readStream match: $f action: [ : r | 'Recognized: ' , r asString].

Here is a more complex parse. This is an excerpt from a Smalltalk parser. Note that streams do not have to contain Characters. Here the input is a stream of tokens which was created by a scanner also built in MEPS.

STBinaryExpression class from: input startingWith: start " binaryExp = unaryExp binaryMessage+" ^input match: STUnaryExpression and:[ input matchOneOrMore: STBinaryMessage action: [: r | r ]] action: [:oc | self new unaryExpression: oc first ; binaryMessages: oc second]

A parser is any object which implements the interface #from:<aPositionableStream> startingWith: <peekElement>. The following are all parsers:

"Base Smalltalk objects" $f 'foobar' [:input | input match: 'foo' and: 'bar' action: [ : oc | oc ]] "Classes can be parsers of their instances" STBinaryMessage "Regular expressions" 'foo|bar' regex "MEPS parsers which understand various combinatorial methods" 'foo' meps "wraps a string parser in a meps parser" 'foo' meps , 'bar' "combine 2 string parsers" 'foo' meps | 'bar' 'foo' meps ! [:r | 'recognized: ' , r] "add an action to a string parser" 'foo' meps range:3 to:7 "as in regular expressions" 'foo' meps oneOrMore "or zeroOrMore, zeroOrOne. these use #range:to:"

Parsers can be combined in several ways, for example:

Using a message to the input positionableStream: 'foobar' readStream match: 'foo' and: 'bar' action: [ : oc | FooBar new foo: oc first ; bar: oc second] Using a block: foobarParser := [:input | input match: 'foo' and: 'bar' action:[ : oc | FooBar new foo: oc first bar: oc seconds ]]. 'foobar' readStream match: foobarParser action: [ : r | r ] Using a class: Foobar class from: input startingWith: peek ^input match: 'foo' and: 'bar' action: [ : oc | self new foo: oc first ; bar: oc second] 'foobar' readStream match: Foobar action: [ : aFoobar | aFoobar ] Using regular expressions: 'bar' readStream match: 'foo|bar' regex action: [ : fooOrBar | Foobar new: fooOrBar ] (New). Using an instance of Meps or one of its subclasses: foobarparser := 'foo' meps , 'bar'. 'foobar' readStream match: foobarparser action:[: oc | Foobar new foo: oc first bar: oc last]