Programming Assignment 6 - Unit Checking

Advanced Programming II, Spring 2003


Due Date

This assignment is due by 2:00 p.m. on Tuesday, 15 April.

See the assignment turn-in page (last modified on 21 January 2003) for instructions on turning in your assignment.

Background

The International System of Units (abbreviated SI after (some of) the initials of the French version of the name) comprises seven basic units, three of which are the meter (abbreviated m), the gram (abbreviated g) and the second (s).

The basic units can be used to define other units. For example, speed can be defined as

mps = m/s

Units can also be defined as a multiple (called a scale factor) of another unit:

cm = m/1000
foot = cm/30.38

Units can also be defined as a combination of scale factors and other units

acre = foot^2/43560

Over the years, many people have proposed adding SI (or similar) units to programming languages to provide another source of protection against programming errors. For example, given the variable declarations

int age year;
int height m;

the statement

height = height + age

is legal in C++ (because both are integers) but would be illegal if units were taken into account because you can't meaningfully add years to meters. Units take part in operations along with their associated values. The following code

double distance m;
double time     s;
double speed  mps;

speed = distance/time

is valid because dividing meters by seconds gives you the same units as mps (assuming the definition given above). Conversions between units, where defined, are done automatically. The code

double heighti inches;
double heightf   foot;

heightf = heighti

is valid because (let us assume) a foot has been defined as 12 inches (and an inch, in turn, has been defined as 0.0254 meters).

Problem

Write a simple, SI-unit-enhanced four-function calculator. The calculator reads equations from std-in and writes computed values to std-out.

Input

Input consists of a sequence of zero or more statements, with zero or one statements appearing on each line. Statements may be one of three types: a unit definition, a variable declaration or a variable assignment. These statements may be input in any order.

A unit definition has the form:

unit-name is unit-equation

A unit-name is a sequence of one or more letters (case doesn't matter). A unit-name is unique; it must appear exactly once to the left of the is in a unit definition.

A unit-equation is either

unit-equation unit-operation unit-equation or
( unit-equation ) or
unit

A unit is one of the pre-defined units meters, grams or seconds, an already defined unit, or a number.

m | g | s | unit-name | integer | double

A unit-operation is either multiplication, division, or exponentiation.

* | / | ^

The right-hand argument to the exponentiation operator must be a number; the unit-equation m^0.5 is syntactically valid, while the unit-equation m^s is syntactically invalid. Exponentiation has higher precedence than does multiplication and division and is left associative; multiplication and division have the same precedence and are also left associative. Parenthesis alter precedence in the usual way.

A variable declaration has the form

var-name : unit-spec

A var-name has the same syntax as a unit-name. A unit-spec is either a unit-name or a unit-equation

unit-spec : unit-name | unit-equation

When defined, a variable contains an undefined, non-numeric value. Because the value is non-numeric, it cannot legally be used in a computation.

A variable-assignment has the form

var-name = equation

A var-name has the same syntax as a unit-name. An equation is either

equation operation equation or
( equation ) or
value optional-unit-spec

A value is either an integer, a double or a variable.

value : int | double | var-name

An operation is one of the four standard operations.

operation : + | - | * | /

An optional-unit-spec is either a unit-spec or nothing.

optional-unit-spec : unit-spec | empty

Output

After reading all input, your program should output one of two things, depending on whether or not any errors were discovered. If the input was without error, your program should write to standard out the final values of all variables defined using the following format:

var-name number optional-unit-spec

If var-name is a scalar value then the unit-spec will be missing. Each unit-spec should be in simplest form possible. A unit-spec is in simplest form if

  1. Repeated multiplications are replaced by exponents. For example inch*inch is not in simplest form; inch^2 is in simplest form.

  2. All divisions are carried through. For example, s*m/s is not in simplest form; m is in simplest form.

  3. All unit definitions are replaced by the associated units. For example, if acre is defined to be foot^2/43560, then foot^2/minute is not in simplest form; acre/minute is in simplest form. Two units that are a constant factor of one another do are of equivalent simplicity.
Note the proceeding notion of simplified units applies to output only.

If the input contains errors, either in syntax or use, then the only output that should appear are error messages written to std-err. If any errors are found in unit definitions or variable declarations, then all such errors should be printed, and nothing should be printed about variable assignments. For example, if the input is

foot is m + s
v: furlong
time: s
len: m
v = time + len

The error messages about foot's definition and v's declaration should be output, but no error about v's assignment should be printed to std-err.

If both the unit definitions and variable declarations have no errors, then all errors discovered in the variable assignments should be printed to std-err and no variable assignments should be printed.


This page last modified on 7 April 2003.