Logo

14.1.6 Creating an MSE parser

The grammar provides a means to digest the input from a syntactic point of view. The default result of parsing the input using this grammar is an array. In most cases this array is not at all satisfactory. Instead, we need to produce an output that matches our problem.

Let us consider using the MSE grammar from Section 14.1.4 for a simple input.

mseString := '((FAMIX.Package))'.
ExampleMSEGrammar parse: mseString.
"--> an Array($( an Array(an Array($( a PPToken(FAMIX.Package) nil #() $))) $))"

Let us supposed that we merely want to produce a regular Smalltalk nested array out of input. There is a lot of unwanted cruft that we would like to get rid of, such as not printing a PPToken explicitly, but only get the name of the element.

To solve this problem, we subclass the grammar class with a parser class that will take care of the desired transformation.

ExampleMSEGrammar subclass: #ExampleMSEArrayParser
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'MSEParserExample'

Before we go any further, we write a test. To do this we mirror the hierarchy of parsers with a hierarchy of tests:

ExampleMSEGrammarTest subclass: #ExampleMSEArrayParserTest
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'MSEParserExample'
ExampleMSEArrayParserTest>>testElementName
super testElementName.
self assert: result = 'ABC.XYZ'

The first line, simply calls the test defined in the super class (see Section 14.1.5). Because the test stores the parsing result result in the result instance variable, we can use this instance variable for writing the assertion.

The test fails as expected. To make it work, we now have to override the elementName definition in the parser class and specify how the output should be transformed:

ExampleMSEArrayParser>>elementName
^ super elementName

==> [:token | token value ]

The output transformation is achieved through the ==> operator. This operator takes as input the value returned by the parser and returns the result of evaluating the block. In this case, we simply want to extract the string value out of the token object.

With this change, the test becomes green, and running the example yields:

mseString := '((FAMIX.Package))'.
ExampleMSEArrayParser parse: mseString.
"--> an Array($( an Array(an Array($(FAMIX.Package nil #() $))) $))"

Add a Note