Parsing an Expression. McGraw-Hill The Complete Reference Fourth Edition
Anúncio
Anúncio
966
C + + : T h e C o m p l e t e R e f e r e n c e
This routine gets the first operand, the operator, and the second operand to perform the first operation and then gets the next operator and operand to perform the next operation, and so on. However, if you use this basic approach, the expression 10 – 2 * 3 evaluates to 24 (that is, 8 * 3) instead of 4 because this procedure neglects the precedence of the operators. You cannot just take the operands and operators in order from left to right because the rules of algebra dictate that multiplication must be done before subtraction. Some beginners think that this problem can be easily overcome, and sometimes, in very restricted cases, it can. But the problem only gets worse when you add parentheses, exponentiation, variables, unary operators, and the like.
Although there are a few ways to write a routine that evaluates expressions, the one developed here is the one most easily written by a person. It is also the most common.
The method used here is called a recursive-descent parser, and in the course of this chapter you will see how it got its name. (Some of the other methods used to write parsers employ complex tables that must be generated by another computer program. These are sometimes called table-driven parsers.)
Parsing an Expression
There are a number of ways to parse and evaluate an expression. For use with a recursivedescent parser, think of expressions as recursive data structures—that is, expressions that are defined in terms of themselves. If, for the moment, we assume that expressions can only use +, , *, /, and parentheses, all expressions can be defined with the following rules: expression
−> term [+ term] [− term] term
−> factor [* factor] [/ factor] factor
−> variable, number, or (expression)
The square brackets designate an optional element, and the
−> means produces. In fact, the rules are usually called the production rules of the expression. Therefore, you could say:
"Term produces factor times factor or factor divided by factor" for the definition of term.
Notice that the precedence of the operators is implicit in the way an expression is defined.
The expression
10 + 5 * B
C h a p t e r 4 0 : P a r s i n g E x p r e s s i o n s
967 has two terms: 10, and 5 * B. The second term contains two factors: 5 and B. These factors consist of one number and one variable.
On the other hand, the expression
14 * (7 – C) has two factors: 14 and (7 – C). The factors consist of one number and one parenthesized expression.
The parenthesized expression contains two terms: one number and one variable.
This process forms the basis for a recursive-descent parser, which is a set of mutually recursive functions that work in a chainlike fashion and implement the production rules.
At each appropriate step, the parser performs the specified operations in the algebraically correct sequence. To see how the production rules are used to parse an expression, let's work through an example using this expression:
9/3 – (100 + 56)
Here is the sequence that you will follow:
1. Get the first term, 9/3.
2. Get each factor and divide the integers. The resulting value is 3.
3. Get the second term, (100 + 56). At this point, start recursively analyzing the second subexpression.
4. Get each term and add. The resulting value is 156.
5. Return from the recursive call, and subtract 156 from 3. The answer is –153.
If you are a little confused at this point, don't feel bad. This is a fairly complex concept that takes some getting used to. There are two basic things to remember about this recursive view of expressions. First, the precedence of the operators is implicit in the way the production rules are defined. Second, this method of parsing and evaluating expressions is very similar to the way humans evaluate mathematical expressions.
The remainder of this chapter develops three parsers. The first will parse and evaluate floating-point expressions of type double that consist only of constant values. Next, this parser is enhanced to support the use of variables. Finally, in the third version, the parser is implemented as a template class that can be used to parse expressions of any type.
Download
Anúncio