4. Times/Divide

Back Home Up Next

It's time to add in multiplication and division.

Multiplication and Division

Here's a shot at it with those nasty left-recusion form of productions:

element := number | ( expression )
term := element | term * element | term / element
expression :=  term | expression + term | expression - term

Of course, we can't use them in this form. But it may help to see them, anyway.

There's a new thing going on here, now -- binding priority. We want the multiplication and division to take place before any addition or subtraction, in the absence of parenthesis. (Or, we will if we ever get around to actually calculating values.) So, initially, we start out considering every algebriac expression as an expression. An expression can then be some combination of plus and minus terms, not times and divide -- not yet, anyway. Only in a term do we find multiplication and division. By layering the productions this way we can achieve the priority we want.

Look at a possible example and see if you can see how it matches up with the above productions::

2 + 6 * 5 - 5 / 3

Since we already know those productions are going to be a problem, I won't bother breaking it down, step by step. Hopefully, you can see that it probably works ... except for the left-recusion problem.

So, let's just hop over to a right-recursive form we can use to code a useful predictive recursive descent parser. (What a mouthful, eh?)

morefactors :=  * factor morefactors | / factor morefactors | <null>
factor := ( expression ) | number
moreterms := + term moreterms | - term moreterms | <null>
term : factor morefactors
expression := term moreterms

Take a close look at the above productions. The basic idea is that an expression is groups of things added and subtracted from each other and that each of those things are groups of still other things multiplied or divided together. By thinking this way, the multiplications and divisions are automatically given priority over additions and subtractions.

You may also notice the similarity of the new productions. I've again renamed them, though. I hope you won't mind. In any case, there's a pattern here you can recognize.

Coding?

Well, I think you can probably guess about how we might code up something to fit the above productions:

FUNCTION Factor% (eqpos AS INTEGER, eq AS STRING)

    DIM status AS INTEGER

        SkipSpaces eqpos, eq
        IF Match("(", eqpos, eq) THEN
            LET status = Expression(eqpos, eq)
            IF status THEN
                SkipSpaces eqpos, eq
                LET status = Match(")", eqpos, eq)
            END IF
        ELSE
            LET status = Number(eqpos, eq)
        END IF

    LET Factor = status

END FUNCTION

FUNCTION Term% (eqpos AS INTEGER, eq AS STRING)

    DIM status AS INTEGER

        LET status = Factor(eqpos, eq)
        DO WHILE status
            SkipSpaces eqpos, eq
            IF Match("*/", eqpos, eq) THEN
                LET status = Factor(eqpos, eq)
            ELSE
                EXIT DO
            END IF
        LOOP

    LET Term = status

END FUNCTION

FUNCTION Expression% (eqpos AS INTEGER, eq AS STRING)

    DIM status AS INTEGER

        LET status = Term(eqpos, eq)
        DO WHILE status
            SkipSpaces eqpos, eq
            IF Match("+-", eqpos, eq) THEN
                LET status = Term(eqpos, eq)
            ELSE
                EXIT DO
            END IF
        LOOP

    LET Expression = status

END FUNCTION

I've prepared a newly modified source file to illustrate:

EQ_04.ZIP or EQ_04.BAS
An example program that will accept the sum and product expressions.

Let's finish this up, adding in powers.

 

Last updated: Friday, January 13, 2006 23:59