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]