Due date: Thursday, October 19, 2006 at 11:59 pm
For this assignment, you are to use the Standard Template Library and a Complex Number class (that you create) to create an infix expression evaluator. The statements that you must evaluate will be in the form of:
When an <expression> is given by itself in the input, the value of the expression is to be output to standard output.
When an <expression> is preceded by "= <varname>", the value of the expression is stored under the key of <varname>.
When the @ symbol (at) is given as the first non-white space character on the line, the line is to contain a filename. You are to read commands from this file until the end of the file, then return to reading from the standard input. If you encounter the . command (see below), quit the program. If you encounter the # command (see below), echo the line to the standard output. The @ command is only valid when reading from the standard input.
When the # symbol (pound/sharp) is given as the first non-white space character on the line, treat the line as a comment and ignore the entire line, except when the program is reading from a file (see the @ command above). In this case, echo the comment line to the standard output.
When the ? symbol is given as the first non-white space character on the line, print out some help regarding the commands allowed by the program and how to use them.
When the . symbol (period) is given as the only non-white space character on the line, quit the program. Beware of <expression> statements that start with a floating point value such as .5.
An <expression> is any infix expression that uses the following operators:
Operator | Associativity | Precedence | Operation | |
---|---|---|---|---|
( ) | Left to Right | Highest | Parenthesized Expression | |
- | Right to Left | Unary Minus | ||
^ | Right to Left | Exponentiation | ||
*, / | Left to Right | Multiplication and Division | ||
+, - | Left to Right | Lowest | Addition and Subtraction |
The operands can be either a <varname> or a numeric constant. The <varname> can be any string starting with a letter in either upper or lower case and then containing either letters (upper or lower case) or digits. The constants can be integers, floating points or complex numbers. The integers and floating point numbers can be signed. The complex numbers will be in the form of NR+NIi, where N can be any positive or negative integer or floating point value. Note, positive numbers are expected to be written without the "+" sign, since unary plus is not a known operator in this problem.
For each <expression>, you will first need to convert it from infix to a postfix expression and then evaluate the postfix expression. The algorithms for both of these are given below and contained in the data structure book written by Mark Allen Weiss, Data Structures & Algorithm Analysis in C, starting on page 72 (on page 103 in the C++ edition). This book is used for CS 202. Both of these algorithms use a stack. You must use the STL class stack for these algorithms. In the infix to post conversion algorithm, you will most likely need to have the stack be a stack of operators. In the evaluation algorithm, you will most likely need to have a stack of complex numbers.
The input will expect only one statement per line. If the statement is to be written on multiple lines, a backslash "\" will be used at the end of each line to indicate the statement will be continued onto the next line. To deal with this, store each expression in the STL class vector. This will allow us not to worry about the unlimited maximum size of each statement.
To convert from infix to postfix, we translate one vector (in infix form) to another vector (in postfix form). As the infix vector is scanned from left to right, when an operand is encountered, it is moved directly from the infix vector to the postfix vector. When an operator is encountered in the infix vector, it is not moved directly to the postfix vector, instead it will be pushed on the stack. Depending on what operand is encountered, we may pop operands from the stack before pushing the current operand.
The postfix vector is now scanned from left to right. When an operand is encountered, its value is pushed onto the stack. When an operator is encountered, some number of values are popped from the stack (two for binary operators, one for unary operators), the operation indicated by the operator is performed and the result is pushed onto the stack (pay attention to which value is the left-hand-side operand and which is the right-hand-side operand). If the stack does not contain two values when an operator is encountered, an error has occurred. When we reach the end of the postfix expression, there should be only one value left on the stack which is the value for the <expression>. If there is not a single value on the stack, then an error has occurred.
The exponentiation operator is to have its second operand value as an integer value. However, if a non-integer value is given, do NOT specify it as an error (yet). If the second operand is not an integer convert it to an integer. This integer must be a value greater than or equal to zero. If a negative value is given, it is an error.
The division operator must not have the second operand value as zero. If a zero value is given, it is an error.
Note: the use of the postfix vector can be avoided, but it is up to you to determine how this is done. However, use of the infix vector will make your life much easier, so use it!!
The <varname>'s are to store the values in the STL class map. This will allow a value evaluated in one statement to be used in another statement. When the operand in an <expression> is a <varname>, your program is to retrieve the value from the map. You must check that <varname> already has a stored value. If not, then an error has occurred. For a statement that begins with an equal sign, you are to store the value of the <expression> (if no error occurred in the <expression>) into the map.
val1+(-anotherValue+-32+5i)*-2The hard part will be determining between the addition operator and the plus sign used to separate the real and imaginary parts of a complex number and between the subtraction operator and the minus sign to indicate a negative constant. If you plan to go for this extra credit, you must specify this in your README file.
unary - | change sign of real and imaginary parts |
* | multiplication - use polynomial multiplication (a+bi) * (c+di) = ac + adi + cbi + bdii = ac + adi + cbi - bd |
/ | division X / (a+bi) = (a+-bi) * X / (a2 + b2) |
binary + | addition |
binary - | subtraction |
= | assignment |
<< | stream output |
For the stream output operator, <<, if the value has no imaginary part, only the real part should be written (i.e. the value of 5.275+0.0i should output as 5.275). Also, if both the real and imaginary parts have no fractional value, the value should be written as an integer (i.e. 3.0+0.0i should be 3, 5.0+9.0i should be 5+9i, 0.0+2.0i should be 0+2i. However, -3.0+-3.14159i should be -3.0+-3.14159i). The <math.h> library function modf() may be useful for this conversion.
You are not required to overload the stream input operator, >>, because the assignment first has you read the input into a vector. You will want to write a method (or maybe a constructor!) that takes the infix vector information as parameters and fills/creates an instance of type complex with the proper values. In doing this, as a numeric constant is encountered as an operand, your program must determine if it is an integer constant, a floating point constant or a complex constant (do you need to read one or two numeric value). To determine this, scan forward in the vector to see if after the first numeric value is there a plus sign followed by a numeric constant followed by an "i". There will not be any white space in the complex number, the imaginary numeric constant may contain a negative sign and there will always be a real numeric constant preceeding the imaginary numeric constant. The regular expression for the complex constant is:
NUM+(-)?NUMiwhere NUM is a sequence of one or more digits that may contain a single period. The underlined parts will always exists, the "(-)?" means that the minus sign may not exist.
The class Complex must also have a constructor that takes two parameters. The first parameter corresponds to the real part of the complex number, the second parameter corresponds to the imaginary part. Both of these values are to default to zero if not given. Also, they are to allow for either integer or floating point values. An instance that is created with integer values should print out integer values for its output. Write any other constructors, destructor or methods that you feel are necessary.