An Implementor's Guide to the PCalc Polynomial Calculator P. N. Hilfinger REPRESENTATION OF POLYNOMIALS Internally, a Polynomial is a sequence of non-zero terms, stored as a List in canonical order. An empty list represents the 0 polynomial. Each term is represented by an object of type Polynomial.Term. A Term consists of an integer coefficient (type long), and a List of simple factors of the form v^n in canonical order, representing the product of the coefficient and the factors. An empty sequence of factors represents 1, and is used for the scalar term. Each factor is represented as an object of type Polynomial.Factor, which is essentially a pair consisting of a variable (type char) and a non-negative exponent. In fully initialized Terms, no Factor has an exponent of 0, although internally, during the construction of a Term, a Factor may temporarily have a 0 exponent. Except during the actual operation of the add or mult procedures on Polynomials, the contents of Terms, Factors, and Polynomials do not change. Therefore, Terms and Factors may be freely shared once construction of a Polynomial is finished. Several copying constructors allow the creation of new, fresh Terms, Factors, and Polynomials that may be modified before being returned back to the client. BASIC OPERATIONS ON POLYNOMIALS, TERMS, FACTORS To add two Polynomials, p1 and p2, one creates a deep copy of p1 (call this copy r) and then "merges" the terms of p2 into it. That is, for term in p2, we first find the appropriate position in canonical order for it within r (as determined by the Term.compareTo method). If there is no Term in r with matching variables and exponents, then the Term from p2 is simply inserted into r. Otherwise, its coefficient is added to that of the corresponding term in r. Terms that end up with 0 coefficients are removed. To multiply two Polynomials, p1 and p2, we simply take all pairs of terms from p1 and p2, multiply them into a new term, and add that term into a running Polynomial sum. Multiplying consists of multiplying coefficients and adding corresponding exponents. Exponentiation is simply repeated multiplication. Polynomials, Terms, and Factors all have subst (substitution) methods. Their operation is actually quite straightforward. A Polynomial is a sum of terms, so to substitute, we simply add the results of substituting into the terms of the Polynomial. A term is a product of a coefficient and some factors, so to substitute into a Term, we simply multiply its coefficient by the results of substituting into its factors. Finally, a Factor is variable raised to an exponent, so to substitute into a Factor, we either get the Factor itself if there is no substitution for its variable, and otherwise the result of exponentiating its substitution. PARSING The parser is a simple recursive-descent translator---basically a transcription of the description of the input syntax into methods--- one for full polynomial expressions, one for terms, one for factors, and one for substitutions. Each method returns the polynomial represented by the construct it parses. By convention, each function reads all the tokens covered by its syntactic construct, and then leaves the input at the first token of the next construct, first skipping any intervening whitespace (ends of lines). One example illustrates the idea: A Polynomial is defined as a sequence of terms separated by '+'s and '-'s, and possibly beginning with a '-'. Therefore to parse a Polynomial, we 1. Check for a leading '-', and read past it if present. 2. Call the term-parsing method (parseTerm) to parse the first term. This gives us a Polynomial, which we negate (multiply by -1) if there was a leading '-', and then use as the initial value of our accumulated result. 3. Now we loop for as long as we see '+' or '-', first skipping the '+' or '-', then using parseTerm to get the next term, then adding (subtracting) the resulting Polynomial to (from) our accumulated result. 4. When the loop stops, we return the accumulated result. DEFINITIONS An instance of the Defns class provides a dictionary for saving definitions (introduced by DEF). Each parameter list is stored as a String (for 'DEF A(b,c,a) = ...', the saved string is "bca"). Since all definitions are single upper-case characters, we simply use two 26-element arrays to store the argument lists and the bodies of the definitions.