4

I have to write a code to evaluate a postfix notation(reverse Polish evaluation) in Smalltalk. I have gone through the documentation and have also implemented a stack. This is the code I have written so far:

Object subclass: #Rpcalc
instanceVariableNames: 'anArray top'
classVariableNames: ''
poolDictionaries: ''
category: nil !

pop:
    | item |
item := anArray at: top.
top := top - 1.
^item!

push: item
 top := top + 1.
 anArray at: top put: item!

setsize: n
  anArray := Array new: n.
  top := 0! 

evaluate:
       | expression aToken op1 op2 operator answer|
   Transcript show: 'Enter Expression' .
   expression :- stdin nextLine.

   | aStack |
   aStack := Array new: 10 .

   aToken := self getNextToken.
       ((aToken key) = 'operand')
       ifTrue: [push : aToken].

        aToken := self getNextToken.
       ((aToken key) = 'operator')
        ifTrue:  [op1 := pop.
           op2 := pop.
           operator := aToken.
   "if(operator := +)"
   "answer := op1 + op2"

I want to know how to tokenize each element in the expression. For e.g., for the expression, 10 3 + 3 7 * - I need to equate it to a token. If its an operand, it should push it into the stack. If an operator, pop the stack twice to get the operands and evaluate the expression. I am totally new to smalltalk, so I am clueless about the syntax.

2 Answers2

2

You did not specify which Smalltalk dialect you are using. In Squeak, you could use the findTokens: method:

'336 8 4 2 1 + - * /' findTokens: ' '
==> an OrderedCollection('336' '8' '4' '2' '1' '+' '-' '*' '/')

Use isDigit to test if a token is a number:

'336' first isDigit
==> true
'+' first isDigit
==> false

To convert from a string to a number you would use asNumber:

'336' asNumber
==> 336

The whole RPN parser/evaluator can easily be implemented with less than 10 lines of code, but obviously that is your homework to do (hint: no need to implement a stack, there is already one).

codefrau
  • 4,583
  • 17
  • 17
1

I suggest you taking a look at the PetitParser. You can parse the expression you have: 10 3 + 3 7 * into a tokens, like: NumberToken(10), OperatorTocken(+) and then depending on the token you do what you need to. Also don't do

operator = '+' ifTrue: [op1 + op2]

do:

op1 perform: operator with: op2

instead,

Uko
  • 13,134
  • 6
  • 58
  • 106
  • 1
    Using `#perform:` is something you should only do if (a) you're an experienced Smalltalker and (b) you absolutely have to. It ruins introspection, and can easily make your life hell. For an interpreter like this I would say _don't_ use `#perform:with:`. With the explicit check you can see at a glance the supported operations. – Frank Shearar Apr 05 '13 at 07:57