"arithmetic if":: Re: Feature for the next C version

Dave Hamaker dwh at twg-ap.UUCP
Sat Aug 12 12:46:45 AEST 1989


In reference to a discussion which began from an expressed wish for
something like the Fortran "Arithmetic IF" statement (for its clarity
when you want to do different things with the <, ==, > cases of a test),
in article <18868 at mimsy.UUCP>, chris at mimsy.UUCP (Chris Torek) describes
Mesa's "SELECT" as a real world example of a language construct that is
a generalization of C's "switch."

One of my pet ideas concerns the generalization of things like "switch."
There's one wrinkle to the idea which may be hard to do with current
compiler technology.  I just don't know enough about compilers to tell.
But, there's a good chance some of you on the net do know, and would be
willing to enlighten us.

Applying the idea to switch gives:

	switch (lhs) {
		case (rhs1): statements
		case (rhs2): statements
		 ...
		case (rhsN): statements
		default: statements
	}

where:

	the "(lhs)" can be omitted;
	if present, "lhs" is an expression, or a *part* of one;
	("lhs" stands for "left-hand side");

	the "rhs's" are also expressions, or *parts* of same;
	the parentheses around a "rhs" may be omitted if it does
		not contain a colon (":");
	("rhs" stands for "right-hand side");

	neither the "lhs", nor any "rhs", may contain part of a:
		character constant,
		string constant,
		parenthesized sub-expression, or
		any other token
		(this could be relaxed, but it probably would
		 not be wise to do so).

If "lhs" is a complete (non-null) expression, for each "rhs" which is a
complete expression, the text of "lhs" and "rhs" are concatenated around
the text of an "==" operator and the result is evaluated as an expression.
Otherwise, the text of "lhs" and "rhs" are just concatenated and evaluated
as an expression.  Control is transferred to the first case with a non-zero
(true) expression value, otherwise to the "default" label, if present, or
the statement following the switch construct, if not (but see my "aside").

If "lhs" is a complete expression and all "rhs's" are constants, "lhs"
must be evaluated exactly once; otherwise, "lhs" (or parts of it) may be
evaluated more than once, and the constructed case expressions may be
evaluated in any order (even in parallel) and need not all be evaluated, at
the complete discretion of the compiler.  This means that case expressions
with side effects cause undefined results.  Note also that duplicate case
expressions are legal, but that unreachable cases which are detectable at
compile time certainly deserve warning diagnostics.

With this, we could write things like:

	switch (x) {
	case > 0:
		signum = 1;
		break;
	case 0:
		signum = 0;
		break;
	case < 0:
		signum = -1;
		break;
	}

and:

	switch (p < ) {
	case .1:
		...
	case .5:
		...
	default:
		...
	}

Now, it seems pretty straightforward to me to compile the construct as
follows:  First, reserve space for a jump instruction.  Second, follow
this with code generated for the "statements" as the case construct is
scanned.  As this is done, remember the "lhs" and the "rhs's," and
remember where in the generated code each "rhs" points to.  Classify
the "lhs" and each "rhs" as to whether or not it is a valid expression
(by trying to parse them).  Further classify each valid "rhs" expression
as to whether or not it is a constant expression.  Third, when the end
of the switch is reached, reserve space for another jump instruction.
Fourth, follow this with code generated to evaluate the expressions
constructed from the "lhs" and "rhs's" and to jump to the proper point
in the generated code associated with each case label.  Finally, fill in
the first reserved jump slot to go to the evaluation code, and fill in
the second reserved jump slot to transfer to the end of the switch.

The wrinkle I'm worried about is: is this notion of saving some program
text aside, concatenating expressions out of them and then "reparsing"
the internally constructed expressions something you can build with
current compiler-construction tools?  Comments from those in the know?

Aside: If I had my druthers, I'd have switches without a default case
give undefined results when no case matches.  It would be a promise to
the compiler that one of the cases will match, allowing generation of
"leaner" code in that event (perhaps with a warning, which would also
help catch when you mistype "default").  I like sharp tools, but it
would not be appropriate to change this sort of thing in an existing
construct (perhaps a syntax for specifying no default could be added).

-Dave Hamaker
dwh at twg.com
...!sun!amdahl!twg-ap!dwh



More information about the Comp.lang.c mailing list