Parsifal Software

Extensible Interpreter Development Kit
Reference documentation

Extending Interpreters:
Adding Complex Arithmetic


Although the addition of complex arithmetic to an interpreter appears at first to be a significant modification, as it happens, except for the addition of one line of code in the constructor for the Dataset class which predefines i, all of the modifications are confined to the Value class. Although these modifications are extensive, they should be moderately clear to any experienced programmer with a basic understanding of complex arithmetic.

Since the modifications are confined to the files comdefs.h and comdefs.cpp and require no syntactic changes, it is possible to add complex arithmetic to any of the four interpreters in the kit by replacing comdefs.h and comdefs.cpp with the complex versions of these files: complex\comdefs.h and complex\comdefs.cpp.

One of the principal design criteria of the Extensible Interpreter Development Kit was that adding new functionality should consist primarily of adding code to handle the new functionality, not changing existing code. As can be seen by inspecting the summary of changes that follows, this criterion has largely been satisfied except where there are necessary interactions between the existing integerType and realType types and the new complexType.

Modifications to the Value Class


The approach taken to add complex arithmetic support is to modify the Value class so that a value object may contain a complex value. Note that this is substantially more complicated than adding array support. The reason is that support for complex values interacts strongly with the code for integer and real data types.

The modifications required to support complex arithmetic are as follows:

  1. Add a new type, complexType, to the Type enumeration.

  2. Add a struct to the anonymous union that provides storage for the real and imaginary parts of a complex number. The real and imaginary parts of the complex number may be accessed as part.real and part.imag. Note that because of the way unions work in C/C++, the real part can be referred to either as value or as part.real.

  3. Add a constructor to the Value class that will create a Value object containing a complex value.

  4. Modify all other constructors so they initialize the imaginary part to zero. In principle, this is necessary only for integerType and realType constructors, however it seems good programming practice to do it in all cases.

  5. Add complexType cases to the switch statements in the following functions.

  6. Add function objects and entries in the functionTable to handle the following functions:
    • real
    • imag
    • conj

  7. In addition to the new constructor, add the following new functions to the Value class to support the above modifications:

  8. Add string constants for error messages corresponding to new error modes:
    • A complex (or real or integer) operand is required
    • A real (or integer) operand is required

Added Cases

Value(double x, Type t);
Change assertScalar() to assertComplex(), since it is legitimate to initialize a complex value with a purely real value.

Value(const Value &v);
Add code to copy the imaginary part of the argument value.

int isTrue() const;
Return true if either the real part or the imaginary part is not zero.

const Value &print(ostream &f) const;
Add a call to complexToString() to get a string representation of the complex number in the form 17 + 42*i Print the string.

Value &operator = (const Value &v);
Set both real and imaginary parts.

Value &operator += (const Value &v);
There are two cases to be dealt with:
  • The destination is a string and the argument is complex. In this case, invoke the complexToString() function to create a string representation of the complex value.
  • The destination is complex. Do the indicated arithmetic. Note that the imaginary part of an integer or real is zero. Notice that the value can be promoted.

Value &operator -= (const Value &v);
Do the indicated arithmetic and promote the type if appropriate.

Value &operator *= (const Value &v);
Do the indicated arithmetic and promote the type if appropriate.

Value &operator /= (const Value &v);
Do the indicated arithmetic and promote the type if appropriate.

Comparison Operators
Complex numbers are not ordered, so only equality and inequality operators are implemented.

Added Functions

void assertComplex() const;
Throws an InterpreterError exception if the value cannot be construed to be complex.

double magnitudeSquared() const;
Calculates the square of the magnitude of a complex number.

double magnitude() const;
Calculates the magnitude of a complex number.

double getReal() const;
Returns the real part of a complex number.

double getImag() const;
Returns the imaginary part of a complex number.

char *complexToString(char *buf) const;
Creates a string representation of a complex number.

Other Modifications

The following additional modifications were required:
  1. In the constructor for the Dataset class, add a single statement:
      value("i") = Value(0,1);  
    This statement predefines the variable i and assigns to it a value with the real part = 0 and the imaginary part = 1, in other words, this sets i to its customary value in complex arithmetic. Note that electrical engineers might, for the sake of tradition, wish to change this variable to j. If this is done, the complexToString() function should also be changed to use j instead of i.

  2. Additionally, the functions defined in the FunctionTable had to be modified to accommodate complex arguments and complex results. For an explanation of the changes, see any elementary calculus textbook.

Table of Contents | Parsifal Software Home Page

Extensible Interpreter Development Kit
Copyright © 1997-2002, Parsifal Software.
All Rights Reserved.