Related articles |
---|
Automatic Structuring of Unstructured Programs (for C) hendren@lucy.cs.mcgill.ca (1992-05-04) |
Re: Automatic Structuring of Unstructured Programs (for C) adegrey@abcl.co.uk (1992-05-05) |
Re: Automatic Structuring of Unstructured Programs (for C) moss@cs.umass.edu (1992-05-05) |
Newsgroups: | comp.compilers |
From: | moss@cs.umass.edu (Eliot Moss) |
Keywords: | C |
Organization: | Dept of Comp and Info Sci, Univ of Mass (Amherst) |
References: | 92-05-023 |
Date: | Tue, 5 May 1992 14:05:06 GMT |
First, let me offer an opinion: measuring quality of structure by presence
or absence of gotos seems pretty foolish to me. The key thing is whether
a piece of code is readily understood, but any construct can be misused,
and I doubt automatic restructuring will substantially improve the
understandability of a either a very poorly written program or a well
written one. You need to deal with deeper properties than surface syntax.
You also risk disturbing the performance, since sometimes I find I mist
disturb organization in controlled ways to get a compiler to act the way I
want.
As for gotos, I have long felt that they are no problem if used carefully
and judiciously. We have a number of gotos and labels in the main
interpreter loop of a Smalltalk interpreter we wrote. One example is that
there are several places where one might discover that the program has
tried to send a message to an object that has no method for that message,
in which case we must do the special "message not understood" actions. We
put those actions in one place, preceded by a label, and goto that label
as necessary. We also have a label for the place to go to start executing
the next byte code (instruction) in the interpreter. That could perhaps
have been done with a loop, but the loop would be really huge and there's
little point. There are other cases that arise in the interpreter, too.
I would say that falling through from case to case in a C switch statement
is about as dangerous (and occasionally convenient) as gotos.
One way you can make using gotos safer is to document the properties and
predicates assumed true at a label, and check at each goto that you have
satisfied the constraints. Label variables and label arrays are trickier,
though occasionally useful. In the interpreter, we use label variables to
record in the method lookup cache the place to go to execute a particular
method on an object of a particular class. This may be the label for the
code that sets up a new stack frame and starts executing with the first
instruction of the method, or it may be the label for the code for a
primitive such as integer addition. However, all these labels have common
assumptions about the state of the world. Similarly, we use a label array
instead of a switch statement when picking up an instruction and branching
to the code for executing that instruction. This is a little faster than
a switch statement and can be used in multiple places (e.g., at the end of
each instruction's code, avoiding a branch to a common place, which would
put an extra branch into the execution of every instruction). These
"tricks" improved performance by 15%, and I don't think they substantially
undermined the understandability of the interpreter. It all has to do
with *judicious* use of a feature and thinking about those programmers
that will come after you and have to understand and maintain your code
(even you in your future incarnations).
--
J. Eliot B. Moss, Assistant Professor
Department of Computer Science
Lederle Graduate Research Center
University of Massachusetts
Amherst, MA 01003
(413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu
--
Return to the
comp.compilers page.
Search the
comp.compilers archives again.