[squeak-dev] Xtreams up to date

Hannes Hirzel hannes.hirzel at gmail.com
Mon Jan 24 11:14:59 UTC 2011


On 1/23/11, mkobetic at gmail.com <mkobetic at gmail.com> wrote:
> OK, let's try something really simple. The wikipedia page shows a simple
> arithmetic expression grammar.

Hello Martin

Thank you for working out the Wikipedia simple arithmetic expression
grammar into a tutorial style text.

I worked through it and understood it. I adapted the class names so
that it runs in the current Squeak 4.2 out of the box. In addition I
edited it slightly. I think it could be added as to the PEGParser
class. Maybe somebody else like to check it in addition ....


Additional example: Wiki text parsing

In the previous mail you mentioned that you'll add the fileout of the class

   PEGWikiGenerator

I did not get the fileout.

--Hannes


=============================================
PEGParser example

Parsing simple arithmetic expressions

The following may be copied into a workspace
=============================================


"The wikipedia page shows a simple arithmetic expression grammar. Here
it is transcribed for Xtreams:"

simpleArithmeticExpressionGrammarDescription := '

               Number                <- [0-9]+
               Parenthesised      <- "(" Expr ")"
               Value                   <- Number / Parenthesised
               Product                <- Value (("*" / "/") Value)*
               Sum                     <- Product (("+" / "-") Product)*
               Expr                     <- Sum

		'.

"The Value from the wiki grammar was expanded into separate Number and
Parethesised expression productions. It'll hopefully will be clear why
shortly.

You already know how to get a parser from grammar. That's always the
same and for anything more complex you'll probably want to cache the
parser instead of recreating it every time, but this will do fine for
now:"


parser := PEGParser parserPEG
				parse: 'Grammar'
				stream: simpleArithmeticExpressionGrammarDescription
				actor: PEGParserParser new.
				
				
"If you parse the following expression and print the result you'll get"


 parser parse: 'Expr' stream: '3+4*(10-4)' reading actor: nil


{{an OrderedCollection($3) . an OrderedCollection()} . an
OrderedCollection({'+' . {an OrderedCollection($4) . an
OrderedCollection({'*' . {'(' . {{an OrderedCollection($1 $0) . an
OrderedCollection()} . an OrderedCollection({'-' . {an
OrderedCollection($4) . an OrderedCollection()}})} . ')'}})}})}

"which is roughly formatted manually to provide at least some
resemblance of the expression tree"


       #(      #(OrderedCollection ($3 "16r0033") OrderedCollection ())
               OrderedCollection (#
                       ('+' #(OrderedCollection ($4 "16r0034")
                       OrderedCollection (#
                               ('*' #(
                                       '(' #(  #(OrderedCollection ($1
"16r0031" $0 "16r0030") OrderedCollection ())
                                                       OrderedCollection (#
                                                       ('-'
#(OrderedCollection ($4 "16r0034") OrderedCollection ())))) ')')))))))


"This not easy to take apart to work with. To do this you need an
Actor that will receive rule specific callbacks and do whatever is
needed.

In this case we would like to evaluate the expression and return the result.

We create a subclass of PEGActor called
PEGSimpleArithmeticExpressionEvaluator. As we mentioned earlier, the
Actor class provides a pragma based mechanism for expressing rule
specific callbacks. So for programming the Evaluator class you simply
need to write a method for each rule what should be done and annotate
it with a pragma.

Let's first fill in the 'Number' rule to deal convert the digit
collections into numbers:"

PEGSimpleArithmeticExpressionEvaluator>>Number: digits
       <action: 'Number'>
       ^digits inject: 0 into: [ :total :digit | total * 10 +
('0123456789' indexOf: digit) - 1 ]



"With this you can parse numbers"

       parser parse: 'Expr' stream: '3456' reading actor:
PEGSimpleArithmeticExpressionEvaluator new

"Print it gives"
{{3456 . an OrderedCollection()} . an OrderedCollection()}


	parser parse: 'Expr' stream: '3+4+5+6+7' reading actor:
PEGSimpleArithmeticExpressionEvaluator new


"So if you add a method for Sum, that's what it will need to deal with:"

Sum: terms
       <action: 'Sum'>
       ^terms last inject: terms first into: [ :total :next |
               (next first = '+') ifTrue: [ total + next last ]
ifFalse: [ total - next last ] ]



"The Actor pragmas provide another convenience for taking more complex
input apart. You can write the above as

Sum: first rest: pairs
       <action: 'Sum' arguments: #(1 2)>
       ^pairs inject: first into: [ :total :pair |
               (pair first = '+') ifTrue: [ total + pair last ]
ifFalse: [ total - pair last ] ]

"The arguments: keyword simply says invoke this method with elements 1
and 2 of the rule input (terms) as arguments. Obviously the method
must take the corresponding number of arguments as well. So with the
above rules the addition expression should give you 25. "



"The Product rule handling is analogous:"

Product: first rest: pairs
       <action: 'Product' arguments: #(1 2)>
       ^pairs inject: first into: [ :total :pair |
               (pair first = '*') ifTrue: [ total * pair last ]
ifFalse: [ total / pair last ] ]



"Finally the parenthesised expression is rather simple:"

Parenthesised: expression
       <action: 'Parenthesised' arguments: #(2)>
       ^expression

"It receives a three element array: the left bracket, the expression
inside and the right bracket. All we really need to do is return the
expression in the middle. The above is using the arguments: pragma
again to achieve that, the following would be equivalent:"

Parenthesised: expression
       <action: 'Parenthesised'>
       ^expression at: 2


"By now is hopefully clearer why it was useful to factor the Value
definition out into separate Number and Parenthesised rule. Otherwise
we'd have to handle both cases in a single Value: method, which would
make the code messier.


A final parsing example"


parser parse: 'Expr' stream: '((3+4)*2-4)/2' reading actor:
PEGSimpleArithmeticExpressionEvaluator new

5



More information about the Squeak-dev mailing list