CMPS 144L Spring 2020
Lab #4: FPAE's and Stacks

Background

As you should recall from lecture, an FPAE (fully-parenthesized arithmetic expression) is either an integer literal (e.g., "605") or of the form

( E op F )

where E and F are themselves FPAE's and op is a binary infix arithmetic operator (i.e., one of +, , *, or /).

Thus, an FPAE is composed of (up to) four kinds of elements, or tokens: left parentheses, right parentheses, integer literals, and operators. FPAE's that are integer literals are said to be atomic, while those that include one or more operators are said to be composite. Intuitively, an FPAE is an arithmetic expression in which every composite subexpression is explicitly parenthesized. It follows that, in an FPAE, the number of pairs of mated parentheses is equal to the number of operators.

In order to make it easy to identify the individual tokens of an FPAE using a Scanner object (i.e., an instance of the class java.util.Scanner), for Activity #1 we will assume that consecutive tokens in an FPAE are separated by one or more spaces.

Examples of FPAE's:

57 ( ( 5 + 2 ) * ( 72 - ( 8 / 3 ) ) )
( 3 - 15 ) ( ( ( 7 + 9 ) * 10 ) / ( ( 4 * 16 ) / ( 25 - 13 ) ) )


Activity #1

You are given an incomplete version of the FPAE_Utils class. Its two public methods are incomplete, and it is your task to put them into working order. One of them, isWellFormed(), determines whether or not the String passed to it qualifies as a well-formed (i.e., syntactically correct) FPAE. The other one, valueOf(), evaluates the FPAE passed to it, which is assumed to be well-formed.

Several other methods that you should find useful are provided within the class, including a main() method for the purpose of testing your work. The Integer.parseInt() method, which translates a numeral (i.e., a String that is a sequence of decimal digit characters) into the corresponding value of type int, will be vital, too.

You also are given the complete Java class StackViaArray, of which FPAE_Utils is a client. For an example of a client program of StackViaArray, see the ParenthesisMatcher application


isWellFormed()

To determine whether or not a string is a well-formed FPAE, this method uses a stack to hold integer codes that represent left parentheses, operators, and operands.1 You will notice the declarations of the int constants LEFT_PAREN_CODE, OPERATOR_CODE, and OPERAND_CODE in the method.

Here is how the method should work:
As it scans the string from left to right, it pushes onto the stack the integer codes corresponding to any tokens that are not right parentheses. When it encounters a right parenthesis, it pops the stack four times and verifies that what came out were the codes for, respectively, an operand, an operator, an operand, and a left parenthesis. If there is any deviation from this (or if the stack had fewer than four items on it in the first place), the string is not a well-formed FPAE. If, on the other hand, what came out of the stack meets this expectation, it pushes onto the stack the code for an operand and continue scanning.

Assuming that everything has gone well to the point that the last token has been processed, all that remains to verify is that the stack has exactly one element on it and that element is the code for an operand. Otherwise, the string is not a well-formed FPAE.


valueOf()

Consistent with what was demonstrated in lecture, this method uses two stacks, one of which holds operators that have been encountered (but have not been applied yet, because their corresponding right parentheses are yet to be encountered). The other stack holds the values of subexpressions (i.e., operands) that have been evaluated already and that are waiting to have an operator applied to them.

Here is how the method should work:

After the last token is processed, the operator stack necessarily will be empty and the operand stack necessarily will have exactly one value in it, and that will be the value of the FPAE.



Activity #2

A weakness of the isWellFormed() and valueOf() methods that you worked on in Activity #1 is that they assume that adjacent tokens in an FPAE are separated by one or more spaces. The purpose of this activity is to "fix" that shortcoming.

To do so, you are to complete the development of a FPAE_Scanner class. Like the java.util.Scanner class, it has methods hasNext() and next(), as well as a constructor that receives (via parameter) a String "to be scanned". Of course, FPAE_Scanner's constructor "expects" the given String to be an FPAE, but one in which there need not be spaces between consecutive tokens. What needs to be supplied is the body of the next() method.

Enter an FPAE: 45+7*- 367 56 ())
Tokens are as follows:
Token #1: |45|
Token #2: |+|
Token #3: |7|
Token #4: |*|
Token #5: |-|
Token #6: |367|
Token #7: |56|
Token #8: |(|
Token #9: |)|
Token #10: |)|
10 tokens found.

Enter an FPAE:
Tokens are as follows:
0 tokens found.

Goodbye.
To test your work, you can make use of the FPAE_Scanner_Tester application. As shown to the right, it repeatedly asks the user to enter an FPAE and, for each one entered, it lists the tokens returned by consecutive calls to the next() method of an FPAE_Scanner object. (Each displayed token appears between a pair of vertical bars so that you can tell if the token contains any spaces, which it should not.) As the example to the right illustrates, an FPAE_Scanner object is simply for the purpose of identifying the tokens (that one would expect to find in an FPAE) in a String; it "does not care" whether that String is a well-formed FPAE.

If you want to put your FPAE_Scanner class to the acid test, you could do the following. Make a copy of your FPAE_Utils.java file (that you completed during Activity #1) and call the new file FPAE_Utils2.java.

Within the new file:

Then run FPAE_Utils2 and feed to it as input FPAE's in which tokens are adjacent to each other rather than separated by spaces. It should be able to evaluate those FPAE's correctly.


Footnotes

[1] An operand is, in effect, a subexpression all of whose tokens already have been processed. Another way to look at it is that an operand is a subexpression that, had we been evaluating the FPAE instead of checking its well-formedness, already would have been evaluated, and thus reduced to an integer literal.