%% Garbage In, Garbage Out, Sigplan Notices 32,6 (June 1997), 23-27.
%%
\documentclass[twocolumn,epsf]{snBaker}
%\documentstyle[twocolumn,epsf]{article}
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GENERAL COLUMN MACROS (Do not change)
%
% The column series and beginning page number
\ColumnName{Garbage In/Garbage Out}{23}
%
% The column title
\ColumnTitle{COMFY---A Comfortable Set of Control Primitives for Machine Language Programming}
%
% The column editor
\ColumnEditor{Henry G. Baker}
{http://home.pipeline.com/\char'176hbaker1/home.html}{hbaker1@pipeline.com}
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AUTHOR MACROS (Change these to match current author)
%
% The column author and bio
%
\ColumnAuthor{Henry G. Baker}{%
Henry Baker 
has been diddling bits for 35 years, with time off for
good behavior at MIT and Symbolics.  In his spare time, he collects
garbage and tilts at windbags.  This column appeared in ACM {\it Sigplan Notices} 32,6 (Jun~1997), 23-27.
}
%
% The article's actual title
%
\ColumnSubTitle{}	% ??


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DOCUMENT SECTION
%

%%\newcommand{\Image}[2]{ \centerline{\Imagenoc{#1}{#2}} }
%%\newcommand{\Imagenoc}[2]{ \epsfxsize=#2 \epsfbox{#1} }

\begin{document}
\maketitle

\catcode`\@=11

\def\eqalign#1{\null\,\vcenter{\openup\jot \m@th
  \ialign{\strut\hfil$\displaystyle{##}$&$
      \displaystyle{{}##}$\hfil \crcr#1\crcr}}\,}

\def\eqalignno#1{\displ@y \tabskip=\@centering
  \halign to\displaywidth{\hfil$\@lign\displaystyle{##}$
    \tabskip=0pt &$\@lign\displaystyle{{}##}$
    \hfil\tabskip=\@centering
    &\llap{$\@lign##$}\tabskip=0pt\crcr #1\crcr}}

\def\leqalignno#1{\displ@y \tabskip=\centering
  \halign to\displaywidth{\hfil$\@lign\displaystyle{##}$
    \tabskip=0pt &$\@lign\displaystyle{{}##}$
    \hfil\tabskip=\centering &\kern-\displaywidth\rlap{$\@lign##$}
    \tabskip=\displaywidth\crcr #1\crcr}}

\catcode`\@=12

\def\mywedge{\char'136}
\def\mytilde{\char'176}
\def\jacobi#1#2{\hbox{$\left({#1\over #2}\right)$}}
\newtheorem{theorem}{Theorem}
\newtheorem{definition}{Definition}

\noindent
{\it Henry G. Baker\footnote{This previously unpublished note was written June 29, 1976, while the
author was a graduate student at M.I.T.  It has not been modified except for light editing.  This research was supported by the Advanced Research
Projects Agency of the Department of Defense and was monitored by the
Office of Naval Research under contract number N00014-75-C-0661.}\\
Laboratory for Computer Science\\
Massachusetts Institute of Technology\\
545 Technology Square\\
Cambridge, MA  02139}

\begin{quotation}\noindent
Structured programming advocates the elimination of the GOTO from the
set of primitives for a computer language.  Yet at the machine
language level, almost all machines offer only the conditional or
unconditional branch as the basic control primitive.  Vaughan Pratt has
suggested using instead pseudo-non-deterministic programming (as well as the
COMFY name).  We present a new set of machine language control
primitives based on Pratt's suggestion which are simpler to implement
than if-then-else and do-while and are more flexible at the same time.
The machine language implementation of these primitives requires
nothing more complicated than a stack; the size of the stack needed
(exclusive of programmer-defined subroutine control points) is $O(d)$,
where $d$ is the operator depth of the program.  This is much less space
and machine complexity than would be required for a true backtracking
control structure.  The user can emulate if-then-else,
do-while, repeat-until, etc., with macros using these primitives if he
so desires.
\end{quotation}
A machine language program using our primitives is built up from
individual {\it actions} and {\it tests} which are combined into {\it sequences},
{\it alternatives}, and {\it loops}.  Actions are primitive instructions executed
for their side-effects such as ``{\tt add x to accumulator 3}'', ``{\tt move a to
b}'', or ``{\tt increment z}''.  Tests are primitive instructions executed to
produce a boolean value; e.g., ``{\tt x>y}'', ``{\tt a=0}'', or ``{\tt overflow?}''.  Tests
are distinguished from actions in that they can either {\it succeed} or {\it fail},
while actions can only {\it succeed}.  The convention is that if the
predicate value is true then the predicate succeeds, and otherwise it
fails.

The semantics of success and failure depend entirely upon the
semantics of sequences, alternatives, and loops.  A {\it sequence} formed from
the two program fragments {\tt A} and {\tt B}, written ``{\tt A;B}'', is executed by first
executing {\tt A} and if it succeeds then executing {\tt B}.  If {\tt A} fails, then {\tt B}
is not executed and the whole sequence fails.  Likewise, if {\tt A} succeeds
and {\tt B} fails, the whole sequence fails.  COMFY is a poor man's
non-deterministic programming language, because {\it any side effects
produced by a program fragment before failing are not undone in the
course of failing}.  Since ``{\tt ;}'' is obviously an associative operator,
{\it long sequences} can be written without parentheses and still be
unambiguously interpreted; e.g., ``{\tt A;B;C;D}''.  A long sequence will
succeed only if every fragment succeeds; it will fail on the leftmost
failing fragment.

We will abbreviate long sequences of the form {\tt A;A;...;A} ($m$ {\tt
A}'s) as $\hbox{\tt A}^m$, where $m$ is a positive integer.  We also define
$\hbox{\tt A}^0\equiv\hbox{\it succeed}$ for completeness.  This notation is
well-defined due to the associativity of sequences.
\subsection*{Alternatives}
An {\it alternative} consists of two program fragments {\tt A} and {\tt B} linked by the
alternative operator ``{\tt |}'' as in ``{\tt A|B}''.  The semantics of the
alternative are dual to those of the sequence.  First {\tt A} is executed.
If it succeeds, then the whole alternative succeeds immediately without
executing {\tt B}.  If {\tt A} fails, then {\tt B} is executed and its success or
failure becomes the success or failure of the whole alternative
expression.  Like the sequence operator, the alternative operator is
associative, allowing long chains of alternatives to be written
unambiguously without parentheses.  We notice that for a chain of
alternatives to succeed, at least one must succeed and only the
leftmost successful alternative will be executed.  Furthermore, the
chain will fail if and only if all of the alternatives fail.
\subsection*{Loops}
With only sequences and alternatives, only finite (tree-like) programs
can be written.  The loop expression allows us to write programs whose
execution length is not bounded.  A {\it loop} consists of a program
fragment {\tt A} followed by the operator $\infty$, as in ${\hbox{\tt A}}^{\infty}$.  The semantics
of this loop expression are equivalent to ``$(\hbox{\tt A};\hbox{\tt A};...)$'', where ``$...$''
means ``and so on, to infinity.''  In other words, {\tt A} is executed over
and over again until it fails; then the whole loop fails.  If {\tt A} never
fails, then the loop expression will continue executing forever; it
will never {\it succeed}.
\subsection*{Inversion}
Inversion is a monadic operator which takes an expression, executes
it, and inverts the meaning of its success and/or failure.  Inversion
of an expression {\tt A} is written as ``$\neg\hbox{\tt A}$''.  Inversion can not be
simulated by sequences, alternatives, {\it succeed} and {\it fail}, in
an uninterpreted (pure) COMFY because both sequence and alternative
are monotonic operations, composition preserves monotonicity, and
inversion is not monotone.
\subsection*{Subroutine Calling}

COMFY allows the definition of subroutines with mnemonic names.  The
existence of a stack for saving return points is assumed; hence
subroutines can be recursive.  Like most machine languages, COMFY
avoids arguments by avoiding parameters; arguments are the
programmer's responsibility.  Likewise, returned values are the
programmer's responsibility.\footnote{A ``condition code'' is a
convenient place to return the boolean value from a subroutine which
implements a predicate/test.}

In a machine implementation using only one stack, stack (LIFO)
discipline must be maintained by both subroutine call and return as
well as by the sequence, alternative, loop, and inversion primitives.
Therefore, a return from a subroutine cannot be made from other than
parenthesis level zero; this is tantamount to running off the end of
the code of a sequence which implicitly succeeds or running off the
end of an alternative which implicitly fails.

(In this context, we point out that COMFY would make a good control
structure for APL, which currently has none.  The issues COMFY
addresses are all orthogonal to those that APL addresses, so the two
might make a good marriage.  The infix notation and shallow dynamic
variable binding of APL make a good interactive language.  COMFY would
enhance that ease-of-use-interaction feature.)
\subsection*{Syntax}
We will assume from now on that the four operators ``{\tt |}'', ``{\tt
;}'', ``$\neg$'', and ``${\tt\infty}$'' have binding power (precedence) which
increases from left to right in the preceding list.

With these four constructs and the two trivial tests {\it succeed} and {\it fail},
we can simulate many other useful constructs.  Some of the simulations
follow.
\subsection*{If-then-else}
Before trying to simulate the construct ``{\tt if B then A else C}'' in COMFY,
we must define what it means.  The intuitive meaning would be: execute
{\tt B}; if it succeeds, execute {\tt A} and its success or failure becomes the
success or failure of the whole expression; if {\tt B} fails, then execute {\tt C}
and its success or failure becomes that of the whole expression.
These semantics are analogous to the meaning of the Algol ``{\tt if B then A
else C}'' in the case that {\tt A} and {\tt C} are boolean-valued expressions.

But if-then-else in general cannot be simulated exactly with ``$;$'', ``$|$'', and ``$\neg$''!  We mean by
exact simulation one which would place no restrictions on the
expressions {\tt B}, {\tt A}, and {\tt C}.  However, in the important special case that
{\tt B} {\it has no side-effects and is not affected by} {\tt A}'s {\it side-effects}, ``{\tt if B then A else C}'' can be simulated by
``$\hbox{\tt B};\hbox{\tt A}|\neg\hbox{\tt B};\hbox{\tt C}$'', because ``$\neg\hbox{\tt B}$'' protects {\tt C} from executing if {\tt A} fails.  This can be made a bit more readable by
defining ``$\rightarrow$'' to be equivalent to ``{\tt ;}'':
``$\hbox{\tt B}\rightarrow\hbox{\tt A}|\neg\hbox{\tt B}\rightarrow\hbox{\tt C}$''.  Finally, {\it if} {\tt A} {\it cannot fail}, then the simulation optimizes to ``$\hbox{\tt B}\rightarrow\hbox{\tt A}|\hbox{\tt C}$'',
which is exactly BCPL syntax for conditionals.\footnote{In our implementation of COMFY, if-then-else is primitive, so it does not have to repeat the evaluation of {\tt B}, and thereby avoids the limitations that that redundant evaluation entails.}
\subsection*{Do-while}
The semantics for the construct ``{\tt while B do E}'' are not usually defined for the
case where {\tt E} can fail; therefore we are free to define them as we
please.  We emulate this expression in COMFY by $\neg(\hbox{\tt B};\hbox{\tt E})^{\infty}$ which
either loops forever or fails.  It can fail either by {\tt B} failing or {\tt E}
failing.  If the programmer does not wish to terminate the loop upon
failure by {\tt E}, he should instead use $\neg(\hbox{\tt B};(\hbox{\tt E}|\hbox{\it succeed}))^{\infty}$.  Using ``$\rightarrow$'' for
``{\tt ;}'', the while construct becomes $\neg(\hbox{\tt B}\rightarrow\hbox{\tt E})^{\infty}$.
\subsection*{Repeat-until}
The construct ``{\tt repeat E until B}'' can be written in our
language $\neg(\hbox{\tt E};\neg\hbox{\tt B})^{\infty}$.  This works
because of our convention that {\tt E} is executed before {\tt B}, and
any side-effects are not nullified if {\tt B} fails.
\subsection*{Extended if-then-else; LISP's \tt COND}
The extended if-then-else expression, equivalent to LISP's {\tt (COND
($\hbox{\tt B}_1$ $\hbox{\tt E}_1$)($\hbox{\tt B}_2$ $\hbox{\tt
E}_2$)...($\hbox{\tt B}_n$ $\hbox{\tt E}_n$))} can often be emulated as
$\hbox{\tt B}_1;\hbox{\tt E}_1|\hbox{\tt B}_2;\hbox{\tt
E}_2|...|\hbox{\tt B}_n;\hbox{\tt E}_n$ or more readably as $\hbox{\tt
B}_1\rightarrow\hbox{\tt E}_1|\hbox{\tt B}_2\rightarrow\hbox{\tt
E}_2|...|\hbox{\tt B}_n\rightarrow\hbox{\tt E}_n$.\footnote{Of course,
for this emulation the $\hbox{\tt E}_i$ must not fail; this limitation
is removed in the implementation by expressing extended if-then-else
in terms of the primitive if-then-else.}
\subsection*{Case}
Unfortunately, this structured programming primitive resists attempts
to simulate it straight-forwardly in terms of the other primitives.
Therefore, it must remain primitive in order to gain efficiency during
execution.
\subsection*{Backtracking}
Although COMFY does not support true non-deterministic programming,
backtracking can be done explicitly within it.  If, for example, in the
progam {\tt A|B} we would like to undo any side-effects caused by {\tt
A} before failing, we could insert another alternative $\hbox{\tt
A}^{-1}$, which is charged with undoing {\tt A}, i.e. $(\hbox{\tt
A}|\hbox{\tt A}^{-1};\hbox{\it fail}|\hbox{\tt B})$.  Thus, when {\tt
A} fails, $\hbox{\tt A}^{-1}$ is executed to undo {\tt A}'s
side-effects and then fails again so {\tt B} can be executed.
($\hbox{\tt A}^{-1}$ is only a mnemonic device; this $-1$ superscript is
not a COMFY operator.)  If {\tt A} can fail at more than one point, it
may be more convenient to undo many side-effects at once, through
saving and then restoring some state information.  If ``{\tt S}'' is a
save sequence, ``{\tt E}'' is a program which can fail, ``{\tt I}'' is
an ignore-saved-information sequence, and ``{\tt R}'' is a true
restore sequence, then ``{\tt S;E;I|R;}{\it fail}'' will have no
side-effects if {\tt E} fails and will have {\tt E}'s side-effects if
{\tt E} succeeds.
\subsection*{Programming Examples}
We give a few examples to show how the notation is used in real
programming.  The first program is trivial; it prints the integers
from 1 to 10.

In ALGOL-like notation:
\begin{verbatim}
x:=1;
while x<11 do
 begin
  print x;
  x:=x+1
 end;
\end{verbatim}

In COMFY notation:
$$\hbox{\tt x:=1;}\hbox{ }\neg(\hbox{\tt x<11}\rightarrow \hbox{\tt print x; x:=x+1})^{\infty}$$

The second program is a subroutine that computes the greatest common
divisor of positive {\tt X} and positive {\tt Y} and leaves the result in {\tt Y}.

\begin{verbatim}
GCD: while X>0 do
      if X>Y then X:=:Y else Y:=Y-X;
\end{verbatim}

In COMFY notation:
$$\hbox{\tt GCD: }\neg(\hbox{\tt X>0}\rightarrow (\hbox{\tt X>Y}\rightarrow\hbox{\tt X:=:Y | Y:=Y-X}))^{\infty}$$

The third program scans a floating point number in FORTRAN format from
an input stream.  ``{\tt S'string'}'' tests if {\tt 'string'} is next in the input
stream. If not, it fails.  If so, it succeeds and moves the buffer
pointer past {\tt 'string'}.  The program is simply an edited form of the
BNF syntax for these numbers where $\epsilon$ is {\it succeed} and $\emptyset$ is
{\it fail}!  We will not attempt to give an equivalent Algol-like program for
this example.
{\tiny
$$\hbox{\tt NUMBER: INTEGER;}(\hbox{\tt S'.';DIGSEQ});(\hbox{\tt S'E';INTEGER})$$
$$\hbox{\tt INTEGER: }(\hbox{\tt S'+'}|\hbox{\tt S'-'}|\hbox{\it succeed});\hbox{\tt DIGSEQ}$$
$$\hbox{\tt DIGSEQ: }\neg(\hbox{\tt S'0'}|\hbox{\tt S'1'}|\hbox{\tt S'2'}|\hbox{\tt S'3'}|\hbox{\tt S'4'}|\hbox{\tt S'5'}|\hbox{\tt S'6'}|\hbox{\tt S'7'}|\hbox{\tt S'8'}|\hbox{\tt S'9'})^{\infty}$$}
\subsection*{Algebraic properties of sequences, alternatives, loops, and inversions}
Sequences, alternatives, and inversions have a remarkable similarity
to the boolean operators {\it and}, {\it or}, and {\it not}.  In fact, for any boolean
expression used for program control purposes, such as loop or
conditional control, the analogy is exact.  Thus, ``{\tt if A$\wedge$B then C else
D}'' can often be simulated by ``{\tt (A;B);C|D}'' (the parentheses are used only for
emphasis; they are not required here), ``{\tt while A$\vee$B do C}'' is simulated by ``$\neg((\hbox{\tt A}|\hbox{\tt B});\hbox{\tt C})^{\infty}$'' (here the parentheses are required).  Again, we can make these
simulations much more readable by writing ``$\wedge$'' for ``{\tt ;}'' and ``$\vee$'' for ``{\tt |}'';
the above program fragments become ``$\hbox{\tt A}\wedge\hbox{\tt B}\rightarrow\hbox{\tt C}|\hbox{\tt D}$'' and
``$\neg(\hbox{\tt A}\vee\hbox{\tt B}\rightarrow\hbox{\tt C})^{\infty}$''
(assuming ``$\vee$'' is the same as ``{\tt |}'' except for syntactic binding power).

The looping operator ``$\infty$'' reminds one of the ``$\forall x$'' operator of
the first order predicate calculus; it is a ``while'' looping operator
because success keeps it looping.  We can define a dual operator ``*''
such that $\hbox{\tt A}^*\equiv(\hbox{\tt A}|\hbox{\tt A}|...)$.  This is an ``until'' looping operator because
success stops it from looping.

We first list properties which are true, followed by some properties
which are not true in general, but are true for interesting special
cases.

\noindent 1.  $(\hbox{\tt A};\hbox{\tt B});\hbox{\tt C}\equiv\hbox{\tt A};(\hbox{\tt B};\hbox{\tt C})$.  Also, $(\hbox{\tt A}|\hbox{\tt B})|\hbox{\tt C}\equiv\hbox{\tt A}|(\hbox{\tt B}|\hbox{\tt C})$.  (Associativity).

\noindent 2.  $\hbox{\tt A};\hbox{\it succeed}\equiv\hbox{\it succeed};\hbox{\tt A}\equiv\hbox{\tt A}\equiv\hbox{\tt A}|\hbox{\it fail}\equiv\hbox{\it fail}|\hbox{\tt A}$.  (Identities).

\noindent 3.  $\hbox{\it succeed}|\hbox{\tt A}\equiv\hbox{\it succeed}$.  $\hbox{\it fail};\hbox{\tt A}\equiv\hbox{\it fail}$.  (Nil-potence).

\noindent 4.  $\hbox{\tt A}^m;\hbox{\tt A}^n\equiv\hbox{\tt A}^{m+n}$. $(\hbox{\tt A}^m)^n\equiv\hbox{\tt A}^{mn}$.  (Laws of exponents).

\noindent 5.  $\neg\neg\hbox{\tt A}\equiv\hbox{\tt A}$.  (Two-valued logic).

\noindent 6.  $\neg(\hbox{\tt A}|\hbox{\tt B})\equiv\neg\hbox{\tt A};\neg\hbox{\tt B}$. 
Also, $\neg(\hbox{\tt A};\hbox{\tt B})\equiv\neg\hbox{\tt A}|\neg\hbox{\tt B}$.  (DeMorgan's Laws).

\noindent 7.  $(\hbox{\tt A}^{\infty})^{\infty}\equiv\hbox{\tt A}^{\infty}$.  $\hbox{\tt A};\hbox{\tt A}^{\infty}\equiv\hbox{\tt A}^{\infty}$.  $\hbox{\tt A}^{\infty};\hbox{\tt A}^{\infty}\equiv\hbox{\tt A}^{\infty}$.  In fact,
$\hbox{\tt A}^{\infty};\hbox{\tt B}\equiv\hbox{\tt A}^{\infty}$, for any {\tt B}!  (Closure).

\noindent 8.  $\neg\hbox{\tt A}^{\infty}\equiv(\neg\hbox{\tt A})^*$.  Also $\neg\hbox{\tt A}^*\equiv(\neg\hbox{\tt A})^{\infty}$.  (Generalized DeMorgan laws).

\noindent -1.  ``{\tt ;}'' is neither idempotent nor commutative, in general.

\noindent -2.  ``{\tt |}'' is neither idempotent nor commutative, in general.  However,
a true non-determinism would make ``{\tt |}'' both.

\noindent -3.  ``{\tt ;}'' distributes over ``{\tt |}'' only sometimes.  ``{\tt |}'' almost never
distributes over ``{\tt ;}''.

\noindent -4.  $\hbox{\tt A}|\hbox{\it succeed}$ is not the same as {\it succeed}.  Also, $\hbox{\tt A};\hbox{\it fail}$ is not the same as {\it fail}.
\subsection*{Redundancy and Completeness}
DeMorgan's laws tell us that alternatives can be simulated by sequence
and inversion; similarly, sequence can be simulated by alternative and
inversion.  Therefore, at the machine language level, we need only
implement either sequences or alternatives, and can simulate the
other.  However the sets \{sequence, inversion, loop\} and \{alternative,
inversion, loop\} are both independent, meaning that neither set can be
reduced without reducing the power of the language.

Sequences, inversion, and loops are not complete because there are at
least two constructs which have non-optimum COMFY simulations.  One is
the ``case'' statement or ``computed GOTO'' which allows a quick
selection from among a host of alternatives.  The other is the
multiple-exit loop---a loop with several exit conditions, each going
to a different place.  The semantics can be simulated, but only at the
cost of repeating the exit tests after loop termination to determine
what to do next.  For example, a loop with body {\tt B} and
termination conditions {\tt C} and {\tt D} might want to goto {\tt E}
and {\tt F}, respectively, upon termination.  This could be simulated
by $(\hbox{\tt C}\vee\hbox{\tt D}|\neg\hbox{\tt B})^*;(\hbox{\tt
C}\rightarrow\hbox{\tt E}|\hbox{\tt D}\rightarrow\hbox{\tt F})$.
Actually, in this case, repeating the condition for how control got to
that place in the program might be a good idea for readability and
ease in understanding a program.
\subsection*{Sources}
Although the immediate source for COMFY was Vaughan Pratt [Pratt76],
there are some striking similarities between it and a series of
syntax-directed compilers, all called META, started by Schorre
[Schorre64] and continued by Schneider and Johnson [Schneider64].
These META compilers were recursive parsers for deterministic
context-free languages constructed by converting each BNF syntax
equation of a suitable grammar into a recursive subroutine.
Non-determinism was avoided by proper choice of the equations and
clever factoring (property $\hbox{-3}$, above).  Left recursive syntax
equations were rewritten as loops to avoid stack overflow.

Schorre's META II had sequences specified by juxtaposition),
alternatives specified by ``{\tt /}'', loops specified by {\tt \$E}
(meaning $\neg\hbox{\tt E}^{\infty}$ in COMFY), and recursion without
parameters.  Tests and actions were extremely rudimentary; the only
test besides {\it succeed} (called {\tt .EMPTY}) was the comparison of a
character string with an input buffer for a match and update the
buffer pointer if successful.  The only action was {\tt .OUTPUT(...)},
which placed information into an output buffer.

Schneider and Johnson's META-3 added tests which did not reference or
affect an input stream and expanded the class of actions to include
any imperative operation which did not affect the succeed/fail flag.
Thus, it was the first META which could be called a programming
language.

The only significant difference between META's and COMFY's semantics
seems to be in the treatment of sequences.  META's sequences were
required to start with a test; a failure at any other than the first
position caused an error stop (this generalization is due to Pratt).
Presumably, this restriction was to keep the semantics of the language
consistent with that of a true non-deterministic (backtracking)
implementation.  However, the addition of unrestricted tests and
actions in META-3 made that consistency impossible.

The duality of sequence and alternative noticed by Pratt does not
appear to have been known by the META designers.  Furthermore, the
inversion operator which makes this duality explicit was not used by
either META or Pratt; it is new.  Finally, the current definition of
loop in COMFY, which for completeness requires an inversion operator
in the language, is also new.

{\it In a future column, we will show how to program the COMFY
compiler.}
%\vfil\pagebreak[4]
\begin{thebibliography}{7}
\bibitem[Pratt76]{pratt}
Pratt, Vaughan.  Personal communication, 1976.
%
\bibitem[Schorre64]{schorre}
Schorre, D.V.  ``META II---A Syntax-oriented Compiler Writing
Language.''  {\it Proc. 19th ACM Nat'l. Conf.}, Aug. 1964.
%
\bibitem[Schneider64]{schneider}
Schneider, F.W., and Johnson, G.D.  ``META 3---A Syntax-Directed
Compiler Writing Compiler to Generate Efficient Code.''  {\it Proc.
19th ACM Nat'l. Conf.}, Aug. 1964.
%
\end{thebibliography}


\SpewBio
\end{document}
