[comp.sources.misc] "Producer" translates Smalltalk to Objective-C

dietz@zhmti.UUCP (Dieter H. Zebbedies) (08/20/87)

"Producer", A package to translate Smalltalk-80 code to your favorite
object oriented language, Objective-C.

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./Makefile`
then
echo "writting ./Makefile"
cat > ./Makefile << '\Rogue\Monster\'
DOC= README producer.f
.SUFFIXES: .me .i .f
all: README
README: readme.f	; mv readme.f README
.me.i:		; itroff -me mac.me $<
.me.f:		; nroff -me mac.me $< >$$$$.f && mv $$$$.f $*.f
\Rogue\Monster\
else
  echo "will not over write ./Makefile"
fi
if `test ! -s ./mac.me`
then
echo "writting ./mac.me"
cat > ./mac.me << '\Rogue\Monster\'
.\" Must be defined externally
.\" \nN		Chapter Number
.po .5i
.ll 7i
.nr % 1
.ds NM \\nN
.de H
.	tm .H0 \\*(NM-\\n% "\\$1"
.	sp
.(l C
\\s12\\fB\\$1\\fP\\s0
.)l
.	pp
..
.de H1
.	tm .H1 \\*(NM-\\n% "\\$1"
.	uh "\\$1"
.	pp
..
.de H2
.	tm .H2 \\*(NM-\\n% "\\$1"
.	uh "\\$1"
..
.de M
.	tm .M \\*(NM-\\n% "\\$1"
.	uh "\\$1"
..
.de MC
.	tm .MC \\*(NM-\\n% "\\$1"
.	uh "\\$1"
..
.de (C
.	(l
.	sz -2n
.	ls 1
.	ta .25i +.25i +.25i +.25i +.25i +.25i +.25i +.25i +.25i +.25i +.25i +.25i
..
.de )C
.	ta
.	ls 2
.	sz
.	)l
..
.nr fn 1
.ds F \*(NM-1
.de (F
.	ds F \\*(NM-\\n(fn
.	tm .F \\*(NM-\\n% "Figure \\*F: \\$1"
.	(l M F
.	hl
.	sp
.	ce
\fIFigure \\*F:\fP \\$1
..
.de )F
.	hl
.	)l
.	nr fn +1
.	ds F \\*(NM-\\n(fn
..
.de (N
.	(q
\\fINOTE IN DRAFT: \\$1\\fP
..
.de )N
.	)q
..
.de NT
.	(q
\\fINOTE IN DRAFT: \\$1\\fP
.	)q
.	tm .NT \\*(NM-\\n% "NOTE: \\$1"
..
.de C
.nr N \\$1
.ds NA \\$1
.he ''\\*(NA''
.fo 'Brad Cox'%'\\*(td'
.(l C
\\s14\\fB\\$2\\fP\\s0
.sp 2
.)l
.he ''\\*(NA''
.tm .C \\nN-\\n% "\\$2"
.pp
..
\Rogue\Monster\
else
  echo "will not over write ./mac.me"
fi
if `test ! -s ./README`
then
echo "writting ./README"
cat > ./README << '\Rogue\Monster\'




                Producer: Smalltalk-80 to Objective-C Translator


                                  Brad J. Cox
                      Productivity Products International
                                  75 Glen Road
                              Sandy Hook, CT 06482
                                (203) 426 1875.


          Smalltalk-80 is a tool for  turning  raw  concepts  into  working
     software prototypes. Objective-C is a tool for turning proven concepts
     into fast, commercial-quality, production systems. Producer is a  tool
     for  bridging  the gap between prototyping and production by automati-
     cally translating Smalltalk-80 sources into Objective-C  sources.  The
     translation is guided by a rule base in which the programmer describes
     how differences between the Smalltalk-80 prototyping  environment  and
     the   Objective-C  production  environment  should  be  resolved  when
     translating the code.

          At SIGGRAPH-87, PPI will announce a  library  of  user  interface
     components  from which programmers build applications with iconic user
     interfaces.  The library and applications built using it are  portable
     across  diverse  window  systems,  initially X-Windows, SunWindows and
     Hewlett Packard's window system. While the Objective-C user  interface
     classes  are  different from Smalltalk's, they are similar enough that
     Producer can usually bridge the differences with some  hand-tuning  of
     the  translated  output.   We  confidently hope that Objective-C, this
     library and Producer will make automatic translation  of  Smalltalk-80
     prototypes  a  routine  part  of  many companies' software development
     lifecycle.

          I'm distributing Producer to enlist  your  help  in  testing  the
     practicality of this notion.



                                   Disclaimer


          Producer is not a mature software  product  but  an  embryo  that
     could  grow  to maturity someday.  Specifically it is not supported or
     warranteed in any  way.  It  was  written  by  myself,  an  individual
     employed  by PPI, and has been released prior to maturity by myself as
     an individual with the consent of the  company.   This  document  will
     make its strengths and some of its present shortcomings clear.

          However, even in its present state,  Producer  demonstrates  that
     automatic  translation  is technically feasible and its present imple-
     mentation provides a capable foundation on which to build.  Since  the
     market  for Smalltalk-80 translators is insufficient for PPI to pursue
     presently, we've released Producer for you to make what use of it  you
     can.

          I do ask that you keep me informed of your experiences  in  using
     it  in  its  current  state,  and  PPI requests that you feed back any


     Brad Cox                          1                      June 22, 1987







                Producer: Smalltalk-80 to Objective-C Translator


     improvements so that we can offer a fully supported  translation  pro-
     duct in the future. PPI retains the copyright and all other applicable
     rights. For example, you may not sell products that contain  any  part
     of the Producer distribution without PPI's permission.



                                  How it works


          The following is a brief description of how Producer works inter-
     nally.   This  was written from my recollection of how I left the code
     over a year ago. It may be inaccurate in places.

          Producer is basically a compiler. It's lexical analyzer  (written
     in  lex) divides Smalltalk-80 text into lexemes, and its parser (writ-
     ten in yacc) recognizes  valid  lexeme  sequences  and  constructs  an
     abstract  representation  of  the  program  as an expression tree. The
     expression tree consists of instances  of  Objective-C  classes;  e.g.
     Method,  Statement, Expression, Message, and Variable. The grammar was
     derived from the syntax diagrams in Goldberg and Robson; _S_m_a_l_l_t_a_l_k-_8_0:
     _T_h_e _L_a_n_g_u_a_g_e _a_n_d _i_t_s _I_m_p_l_e_m_e_n_t_a_t_i_o_n; Addison Wesley; 1986.

          The grammar was extended to also recognize rules  that  may  also
     appear  in the lexeme stream. Rules are enclosed in { braces } to help
     fend off shift-reduce conflicts from yacc. The parser stores the rules
     in separate data structures for use during code generation.

          At certain points, the parser sends the  top  of  the  expression
     tree  a  gen  message  to  trigger  code  generation[1].  Recall  that
     Smalltalk-80 is an extremely simple language with basically  two  com-
     ponents;  data  references  (variables,  literals,  etc) and messages.
     Rules may influence how each case is treated during code generation.

          Code generation proceeds in two passes. The first  pass  collects
     typing  information  for  each  symbol  and  message  by examining the
     expression tree from the bottom up. The bottom-most nodes  are  either
     literals whose type is immediately obvious (e.g. 1, 2.3, or 'string'),
     or they are symbols whose type can be known or unknown.  Symbol  types
     ____________________
9        [1] I now regard this as a major architectural flaw whenever I  see
     it in any application. It represents a key departure from an important
     but often ignored rule of object-oriented design.  The expression tree
     classes  should  be  abstract  so  that  they could be reused in other
     tools. But their code generation methods pollute the abstraction  with
     knowledge about a particular concrete interface; Objective-C. The code
     generation methods should have been provided in a  separate  hierarchy
     of  classes  that  know  how to connect the abstract classes to one of
     many potential concrete interfaces. This rule is simply a  generaliza-
     tion  of  the model/view/controller paradigm to apply to interfaces of
     any kind, not just user interfaces.



9     Brad Cox                          2                      June 22, 1987







                Producer: Smalltalk-80 to Objective-C Translator


     become known either as the  result  of  a  previous  type  inferencing
     operation  or because their type was specified in a rule. Unknown sym-
     bols default to id when first referenced.

          Most of the internal  nodes  are  messages.   Message  typing  is
     slightly more complicated because any message can have multiple trans-
     lations depending on how the message is used because  different  rules
     may  specify  different  translations for different receiver and argu-
     ments types. The diverse translations may  each  compute  a  different
     type.  Since  we  assign types bottom up, types have been assigned for
     the arguments and the receiver, so a translation for that selector  is
     chosen  by searching a table of possible translations for one matching
     the receiver and argument types.

          In all cases, unless  overridden  by  a  specific  rule,  default
     translations  are  used.  These amount to a fairly literal translation
     from Smalltalk-80 syntax to Objective-C syntax. However exceptions are
     made  for  Smalltalk  literal  constants, which translate to C literal
     constants. In other words, 2+2 translates  to  [2  plus:2],  which  is
     _g_u_a_r_a_n_t_e_e_d  to  fail catastrophically in Objective-C. The integer 2 is
     an object only in Smalltalk!

          The moral:  _N_e_v_e_r  believe  the  translator.  _A_l_w_a_y_s  monitor  it
     closely. Remember the 90-10 rule. The automatic translation concept is
     capable, with suitable rules, of automatically translating only 90% of
     an  application  correctly;  the  other  10% (where the bugs will have
     congregated) is still up to you.



                             Implementation Status


          Producer currently represents about three  man-weeks  of  effort,
     spent  in  two  intensive  bursts  separated by about a year. The most
     recent burst was nearly a year and a half ago.  The first burst was to
     demonstrate  the  feasibility and practicality of the translation con-
     cept. The second burst was in the course of preparing  a  paper  that,
     coauthored  with Kurt Schmucker, will appear in the OOPSLA-87 proceed-
     ings. A (very) early draft is provided with this distribution.

          For being developed so quickly, the translator does an  effective
     job  of  translation.  I refer you to the paper for discussions of the
     strengths and limitations of the translation  concept.   This  section
     discusses  the current implementation of this concept, the items on my
     own must-do list for the planned, but not yet completed,  third  stage
     of Producer's evolution.

     (1)  Smalltalk-80 fileout format uses '!' delimiters in a fashion that
          I  was never able to formalize correctly in Producer's yacc gram-
          mar. The symptom is that  the  translator  will  generate  syntax
          errors  in nearly every translated file for certain of these del-
          imiters. I'm told that fileout format has been  documented  in  a


     Brad Cox                          3                      June 22, 1987







                Producer: Smalltalk-80 to Objective-C Translator


          paper  somewhere, but I've never worked the repairs back into the
          code. The fix should be local to gram.y.

     (2)  The translator loads its rule base by reading files of  rules  as
          if  they were concatenated with the sources to be translated. The
          rule-specification syntax is abysmal, primarily  because  it  was
          chosen  to  minimize  the  amount of time I spent struggling with
          shift-reduce conflicts from yacc, rather than  making  the  rules
          intelligible  to  users. Smalltalk's formal grammar seemed unrea-
          sonably difficult for yacc to swallow, and I suspect the  problem
          may  lie  in  some  mistake I've made in translating Smalltalk-80
          syntax diagrams into yacc specifications.

     (3)  The program contains extensive provisions for reporting its cogi-
          tations in type inferencing. The various error, warning, logging,
          and debugging messages need to be tuned for greater utility.

     (4)  The code was based on an as yet unreleased libary (phylum) called
          "Substrate",  which  supports  features  that  are not yet in our
          standard product set, like  Blocks,  Coroutining,  and  exception
          handling.   I made a fast editing pass to remove any dependencies
          on these nonstandard library  features.  I  also  added  a  file,
          Substrate.h,  that defines stylistic conventions that I adhere to
          in all my work. See USE, IMPORT, EXPORT, etc in the sources.

          The preceeding problems are superficial and easily repaired.  The
     following  ones  are  somewhat  more  substantial in that they involve
     design work in addition to coding work.

     (1)  The type inferencing machinery infers types of  newly-encountered
          (unknown)  messages and variables by seeing how they are combined
          with variables and messages whose types are known apriori or else
          determined  earlier through inferencing.  The only types that are
          known apriori are literals like 1, 2.3, or  'string'.  This  gen-
          erally  provides  insufficient  typing  information from which to
          infer anything useful, so you should generally  provide  variable
          rules  to  pin  down  types for key instance variables and method
          arguments You do this with rules that state, in effect, that `the
          type of the Smalltalk variable named foo is int, and the variable
          is called foobar in Objective-C'.  Presently  rules  have  global
          scope.  If different Smalltalk classes use the name, foo, in ways
          that should be translated differently, different rule  sets  must
          be  provided  manually  to  the translator. Creating and managing
          these application-specific rules sets  adds  to  the  translation
          effort  and tends to make rules non-reusable across translations.
          The rules should be organized with a scoping  mechanism,  ideally
          one based on inheritance.

     (2)  The inferencing logic is ad-hoc and quite possibly slow.  However
          the  main  bottleneck seems to be loading the rule-base; transla-
          tion  speed  has  never  been  a  real  problem.  Inferencing  is
          presently  deductive,  and  a more inductive scheme based on both
          forwards and backwards reasoning  might  produce  higher  quality


     Brad Cox                          4                      June 22, 1987







                Producer: Smalltalk-80 to Objective-C Translator


          translations.  In other words, the translation of a given message
          expression is determined exclusively by whatever information  can
          be inferred about the types of the receiver and arguments to that
          message (forward reasoning). Backward reasoning would  also  con-
          sider how the results of the expression are used in other expres-
          sions.

     (3)  Producer does not presently handle  non-trivial  uses  of  Blocks
          correctly;  ie.   Block  expressions  that  cannot  be translated
          directly into C conditional expressions like if, while,  or  for,
          which Producer handles just fine already.  Nearly all occurrences
          of Smalltalk-80 Blocks could  be  handled  without  changing  the
          Objective-C  language by adding a trivially simple Block class to
          the library. A named instance  variable  holds  a  pointer  to  a
          static function and indexed instance variables hold _c_o_p_i_e_s _o_f any
          variables that the block accesses in the  instantiation  site[2].
          This  copy  could  be taken entirely automatically by copying the
          instantiation site's stack frame.  However I prefer to have  more
          control  over  space  than that. So I've been using a scheme that
          requires the programmer (and someday  the  compiler)  to  specify
          which  variables are really accessed by the block as arguments to
          the message that instantiates the block; like this

               ... {
                IMPORT void aStaticFunction();
                  id var1 = something, var2 = something;
                aBlock = [Block function:aStaticFunction args:2, var1, var2];
                [anyObject do:aBlock];
                ...
               }
               LOCAL void aStaticFunction(instantiationSiteVariables, value1, value2)
                struct { id var1, var2; } *instantiationSiteVariables;
                id value1, value2;
               {
                if ([instantiationSiteVariables->var1 someMessage])
                  ...
               }


          The block will call the function when anyObject sends  the  block
          one  of  several  evaluation  messages  (value:arg1 or value:arg1
          value:arg2 or ...). The first argument is a  _p_o_i_n_t_e_r  to  block's
          copy  of  the  instantiation site's variables. The trailing argu-
          ments contain the arguments that the invocation  site  passed  in
          the value: message.  I've used this approach extensively by writ-
          ing the static functions by hand, and am trying to get our  staff
          to  extend  the  language  to provide some kind of language-level
          support to make the syntax simpler.  This approach could be,  but
          has not yet been, taken by Producer.
     ____________________
9        [2] In Smalltalk-80, the block seems to have access to the  instan-
     tiation  site's  variables,  so that the block can change variables in


9     Brad Cox                          5                      June 22, 1987







                Producer: Smalltalk-80 to Objective-C Translator


          The inferencing machinery's primary current virtue is that it can
     be made to work for selected test cases. It leaves lots to be desired.
     Call me if you decide to extend it so that I can  prevent  unnecessary
     duplication of effort.



                             About the distribution


          The top level of the distribution consists of

         total 88
         -rw-r--r--  1 cox           181 Jun 22 14:32 Makefile
         -rw-r--r--  1 cox         26592 Jun 22 14:30 README
         drwxr-xr-x  2 cox           512 Jun 22 14:19 example
         -rw-r--r--  1 cox           166 Jun 16 13:18 log
         -rw-r--r--  1 cox           997 Jun 15 11:09 mac.me
         -rw-r--r--  1 cox         26751 Jun 15 11:02 producer.me
         -rw-r--r--  1 cox         21444 Jun 22 14:29 readme.me
         drwxr-xr-x  2 cox           512 Jun 12 10:22 rules
         drwxr-xr-x  2 cox          3072 Jun 22 14:31 src

     The Makefile governs formatting of  the  two  documents;  this  README
     (from   readme.me)   and  the  draft  of  the  OOPSLA-87  paper  (from
     Producer.me). The mac.me file contains text formatting macros that are
     common to both papers; used like this:

         nroff -me mac.me Producer.me >Producer.f


          The rules directory contains  a  single  file,  generic.ru,  that
     represents a first pass at an application-independent rules base. This
     set of rules translate Smalltalk to the conventions used in my  proto-
     type version of the user interface library.

          For example, it translates Smalltalk Integer operations to C  int
     operations,  and  it translates Smalltalk Point operations to C macros
     that manage points as type PT; a pair of 16-bit coordinates in  a  32-
     bit  C  int.   For  example,  pt(x,y) invokes a C macro that trims and
     shifts two ints, x and y, to fit side by side  in  a  32-bit  integer,
     ptPlus(p,q)  invokes  a  macro  that  computes  the  vector sum of two
     points, p and q, etc.

         rules:
         total 35
     ____________________
9     the instantiation site. In Objective-C the block receives  a  copy  of
     the  variables  and cannot use them to communicate with the instantia-
     tion site. I believe that  this  is  the  sole  functional  difference
     between the two schemes.



9     Brad Cox                          6                      June 22, 1987







                Producer: Smalltalk-80 to Objective-C Translator


         -rw-r--r--  1 cox         35567 Jun 12 10:22 generic.ru


          The src directory contains a fragment from  the  video  animation
     program  that  appears  at  the  end  of  the Smalltalk-80 video tape.
     BounceInBoxNode.st is the Smalltalk-80 source file, animation.ru  con-
     tains  the  application-specific  rule  set,  BounceInBoxNode.m is the
     translated version built by Producer as invoked by Makefile[3].

         example:
         total 7
         -rw-r--r--  1 cox          1730 Jun 16 10:24 BounceInBoxNode.m
         -rw-r--r--  1 cox           868 Jun 16 10:18 BounceInBoxNode.st
         -rw-r--r--  1 cox           394 Jun 16 10:20 Makefile
         -rw-r--r--  1 cox          2178 Jun 16 10:18 animation.ru
         -rw-r--r--  1 cox           185 Jun 16 10:24 log
         -rw-r--r--  1 cox           239 Jun 16 10:18 st80.h


          The log file records the results of the translation session.  The
     syntax  error  is innocuous, the result of the beforementioned problem
     in the grammar in handling '!' delimiters.

         Producer -c ../rules/generic.ru animation.ru BounceInBoxNode.st >BounceInBoxNode.m
         error 7:BounceInBoxNode.st: tegory:'Graphics-Animation'!! : syntax error
         *** Error code 1 (ignored)


          The src directory contains the sources for Producer, with its own
     Makefile.    The  Substrate.h  header  file,  which  is  automatically
     included by the Producer.h header file, is technically  a  part  of  a
     internal  lower level library, Substrate, on which Producer was origi-
     nally developed. Substrate.h was copied and changed  superficially  so
     that Producer compiles correctly without the Substrate library.

         src:
         total 70
         -rw-r--r--  1 cox           483 Jun 12 10:21 AbstractTranslation.m
         -rw-r--r--  1 cox           282 Jun 12 10:21 ArgumentList.m
         -rw-r--r--  1 cox           897 Jun 12 10:21 Block.m
         -rw-r--r--  1 cox           143 Jun 12 10:21 CharConstant.m
         -rw-r--r--  1 cox          2205 Jun 12 10:21 Class.m
         -rw-r--r--  1 cox           630 Jun 12 10:21 Comment.m
         -rw-r--r--  1 cox           176 Jun 12 10:21 Constant.m
         -rw-r--r--  1 cox          2032 Jun 12 10:21 Expr.m
         -rw-r--r--  1 cox          1243 Jun 12 10:21 FunctionTranslation.m
         -rw-r--r--  1 cox          1484 Jun 12 10:21 Identifier.m
         -rw-r--r--  1 cox          1248 Jun 12 10:21 IdentifierTranslation.m
     ____________________
9        [3] The full source for the animation program is not  provided.  My
     copyright paranoia argued against providing even this fragment.



9     Brad Cox                          7                      June 22, 1987







                Producer: Smalltalk-80 to Objective-C Translator


         -rw-r--r--  1 cox           105 Jun 12 10:21 List.m
         -rw-r--r--  1 cox          1985 Jun 15 11:55 METHODDECLS.m
         -rw-r--r--  1 cox          1384 Jun 15 11:51 Makefile
         -rw-r--r--  1 cox          4302 Jun 12 10:21 Method.m
         -rw-r--r--  1 cox          3136 Jun 12 10:21 Msg.m
         -rw-r--r--  1 cox           583 Jun 12 10:21 MsgArgPattern.m
         -rw-r--r--  1 cox           828 Jun 12 10:21 MsgNamePattern.m
         -rw-r--r--  1 cox          1280 Jun 12 10:21 MsgTranslation.m
         -rw-r--r--  1 cox           775 Jun 12 10:21 MsgTranslator.m
         -rw-r--r--  1 cox          1868 Jun 12 10:21 Node.m
         -rw-r--r--  1 cox           229 Jun 12 10:21 NumberConstant.m
         -rw-r--r--  1 cox          1402 Jun 15 11:27 Producer.h
         -rw-r--r--  1 cox           306 Jun 12 10:21 Return.m
         -rw-r--r--  1 cox           825 Jun 12 10:21 Scope.m
         -rw-r--r--  1 cox          3157 Jun 12 10:21 Selector.m
         -rw-r--r--  1 cox           253 Jun 12 10:21 SelectorConstant.m
         -rw-r--r--  1 cox           457 Jun 12 10:21 StArray.m
         -rw-r--r--  1 cox           492 Jun 12 10:21 Stmt.m
         -rw-r--r--  1 cox           381 Jun 12 10:21 StringConstant.m
         -rw-r--r--  1 cox          1268 Jun 12 10:21 StringTranslation.m
         -rw-r--r--  1 cox          2140 Jun 15 11:38 Substrate.h
         -rw-r--r--  1 cox          1405 Jun 15 11:53 Symbol.m
         -rw-r--r--  1 cox           452 Jun 12 10:21 Template.m
         -rw-r--r--  1 cox           901 Jun 12 10:21 Type.m
         -rw-r--r--  1 cox          1800 Jun 12 10:21 design.me
         -rw-r--r--  1 cox          3271 Jun 12 10:21 gen.m
         -rw-r--r--  1 cox          9007 Jun 12 10:21 gram.y
         -rw-r--r--  1 cox          3601 Jun 12 10:21 lex.l
         -rw-r--r--  1 cox          2212 Jun 12 10:21 main.m
         -rw-r--r--  1 cox           260 Jun 12 10:21 st80.h
         -rw-r--r--  1 cox           259 Jun 15 11:59 y.tab.h


          The files are exactly as I left them nearly a  year  and  a  half
     ago, except for:

     (1)  The addition of this README  document.  An  early  draft  of  the
          OOPSLA-87 paper, sadly prior to Kurt Schmucker's improvements, is
          in Producer.me.

     (2)  One recompilation pass to remove any obvious dependencies  on  my
          private  Substrate  library  and to verify that Producer compiles
          and runs correctly on the standard Foundation library.  I  tested
          the  changes  by verifing that the Makefile in the example direc-
          tory ran to completion, but this is hardly an ironclad guarantee.



                                   Using Producer


          Flags controlling the  translation  process,  source  files,  and
     rules  files are provided on the command line and are processed in the


     Brad Cox                          8                      June 22, 1987







                Producer: Smalltalk-80 to Objective-C Translator


     order they appear.  The flags are[4]

     -d:  Enable debugging functions (dbg()) scattered throughout the code.
          Seldom useful.

     -m:  Enables  the  Objective-C  Foundation  library  message   tracing
          feature. Seldom useful in Producer.

     -a:  Enables the Objective-C  Foundation  library  allocation  tracing
          feature. Seldom useful in Producer.

     -l:  Enables printing of each lexical token as produced by lex. Useful
          only for debugging lex.l.

     -g:  Enables automatic redirection of each class into a separate  file
          based on the class name parsed from the input file. Automatically
          puts class Foobar into file Foobar.m.

              CAREFUL! This puts at risk other files whose  name  might
              coincide with a Smalltalk-80 class name!


     -s:  Generate Smalltalk-80 sources in the output file  as  Objective-C
          comments (the default).

     -c:  Don't generate Smalltalk-80 sources in the output file.

     -i:  Generate information that was thought at one time  to  be  useful
          when debugging rules.

     -M:  Send storeOn: to the message rule  dictionary  just  before  ter-
          minating as a debugging aid.

     -I:  Send storeOn: to the variable rule dictionary  just  before  ter-
          minating as a debugging aid.

          Typically, the generic rules  in  rules/generic.ru  is  specified
     first, then any application-specific rules, then a single Smalltalk-80
     source file.  Unless -g is  set,  the  translated  output  appears  on
     stdout.  The  various  creaks, groans and mumbles that can be elicited
     about the translation process itself appear on stderr.

          For the syntax for writing new rules, refer to  the  examples  in
     generic.ru  and  animation.ru,  and if necessary, the rules section of
     the grammar in gram.y.

          And good luck! Let me know how you fare...

     ____________________
9        [4] I'm working from memory about what these flags mean.  Some  may
     be nonfunctional:



9     Brad Cox                          9                      June 22, 1987



\Rogue\Monster\
else
  echo "will not over write ./README"
fi
if `test ! -s ./readme.me`
then
echo "writting ./readme.me"
cat > ./readme.me << '\Rogue\Monster\'
.C "Producer: Smalltalk-80 to Objective-C Translator"
.(l C
Brad J. Cox
Productivity Products International
75 Glen Road
Sandy Hook, CT 06482
(203) 426 1875.
.)l
.pp
Smalltalk-80 is a tool for turning raw concepts into working software 
prototypes. Objective-C is a tool for turning proven concepts into fast,
commercial-quality, production systems. Producer is a tool for bridging
the gap between prototyping and production by automatically translating 
Smalltalk-80 sources into Objective-C sources. The translation is guided
by a rule base in which the programmer describes how differences between 
the Smalltalk-80 prototyping environment and the Objective-C production
environment should be resolved when translating the code.
.pp
At SIGGRAPH-87, PPI will announce a library of user interface components 
from which programmers build applications with iconic user interfaces.
The library and applications built using it are portable across diverse window
systems, initially X-Windows, SunWindows and Hewlett Packard's window
system. While the Objective-C user interface classes are different from
Smalltalk's, they are similar enough that Producer can usually bridge the
differences with some hand-tuning of the translated output.  We confidently 
hope that Objective-C, this library and Producer will make automatic 
translation of Smalltalk-80 prototypes a routine part of many companies'
software development lifecycle.
.pp
I'm distributing Producer to enlist your help in testing the practicality of
this notion.

.H "Disclaimer"
.pp
Producer is not a mature software product but an embryo that could grow to
maturity someday.  Specifically it is not supported or warranteed in any way.  
It was written by myself, an individual employed by PPI, and has been released 
prior to maturity by myself as an individual with the consent of the company.
This document will make its strengths and some of its present shortcomings
clear.
.pp
However, even in its present state, Producer demonstrates that automatic
translation is technically feasible and its present implementation provides
a capable foundation on which to build. Since the market for Smalltalk-80 
translators is insufficient for PPI to pursue presently, we've released
Producer for you to make what use of it you can.
.pp
I do ask that you keep me informed of your experiences in using it in its
current state, and PPI requests that you feed back any improvements so that 
we can offer a fully supported translation product in the future. PPI retains
the copyright and all other applicable rights. For example, you may not 
sell products that contain any part of the Producer distribution without 
PPI's permission.

.H "How it works"
.pp
The following is a brief description of how Producer works internally.
This was written from my recollection of how I left the code over a
year ago. It may be inaccurate in places.
.pp
Producer is basically a compiler. It's lexical analyzer (written in lex)
divides Smalltalk-80 text into lexemes, and its parser (written in yacc)
recognizes valid lexeme sequences and constructs an abstract representation
of the program as an expression tree. The expression tree consists of 
instances of Objective-C classes; e.g. Method, Statement, Expression,
Message, and Variable. The grammar was derived from the syntax diagrams
in Goldberg and Robson; \fISmalltalk-80: The Language and its
Implementation\fP; Addison Wesley; 1986.
.pp
The grammar was extended to also recognize rules that may also appear
in the lexeme stream. Rules are enclosed in { braces } to help fend off
shift-reduce conflicts from yacc. The parser stores the rules in separate
data structures for use during code generation.
.pp
At certain points, the parser sends the top of the expression tree a 
gen message to trigger code generation\**. Recall that Smalltalk-80
is an extremely simple language with basically two components; data
references (variables, literals, etc) and messages. Rules may influence
how each case is treated during code generation.
.(f
\** I now regard this as a major architectural flaw whenever I see it in any
application. It represents a key departure from an important but often
ignored rule of object-oriented design.  The expression tree classes should
be abstract so that they could be reused in other tools. But their code 
generation methods pollute the abstraction with knowledge about a particular
concrete interface; Objective-C. The code generation methods should have been
provided in a separate hierarchy of classes that know how to connect the
abstract classes to one of many potential concrete interfaces. This rule 
is simply a generalization of the model/view/controller paradigm to apply 
to interfaces of any kind, not just user interfaces.
.)f
.pp
Code generation proceeds in two passes. The first pass collects typing
information for each symbol and message by examining the expression
tree from the bottom up. The bottom-most nodes are either literals whose
type is immediately obvious (e.g. 1, 2.3, or 'string'), or they are symbols
whose type can be known or unknown. Symbol types become known either as
the result of a previous type inferencing operation or because their type
was specified in a rule. Unknown symbols default to id when first referenced.
.pp
Most of the internal nodes are messages.  Message typing is slightly more
complicated because any message can have multiple translations depending on
how the message is used because different rules may specify different 
translations for different receiver and arguments types. The diverse
translations may each compute a different type. Since we assign types bottom
up, types have been assigned for the arguments and the receiver, so a 
translation for that selector is chosen by searching a table of possible
translations for one matching the receiver and argument types. 
.pp
In all cases, unless overridden by a specific rule, default translations
are used. These amount to a fairly literal translation from Smalltalk-80 
syntax to Objective-C syntax. However exceptions are made for Smalltalk
literal constants, which translate to C literal constants. In other words,
2+2 translates to [2 plus:2], which is \fIguaranteed\fP to fail 
catastrophically in Objective-C. The integer 2 is an object only in 
Smalltalk!
.pp
The moral: \fINever\fP believe the translator. \fIAlways\fP monitor it 
closely. Remember the 90-10 rule. The automatic translation concept is
capable, with suitable rules, of automatically translating only 90% of
an application correctly; the other 10% (where the bugs will have 
congregated) is still up to you.

.H "Implementation Status"
.pp
Producer currently represents about three man-weeks of effort, spent in two
intensive bursts separated by about a year. The most recent burst was nearly
a year and a half ago.  The first burst was to demonstrate the feasibility 
and practicality of the translation concept. The second burst was in the
course of preparing a paper that, coauthored with Kurt Schmucker, will appear
in the OOPSLA-87 proceedings. A (very) early draft is provided with this
distribution. 
.pp
For being developed so quickly, the translator does an effective job of 
translation.  I refer you to the paper for discussions of the strengths 
and limitations of the translation concept.  This section discusses the
current implementation of this concept, the items on my own must-do list 
for the planned, but not yet completed, third stage of Producer's evolution.
.np
Smalltalk-80 fileout format uses '!' delimiters in a fashion that I was
never able to formalize correctly in Producer's yacc grammar. The symptom
is that the translator will generate syntax errors in nearly every translated
file for certain of these delimiters. I'm told that fileout format has been
documented in a paper somewhere, but I've never worked the repairs back into
the code. The fix should be local to gram.y.
.np
The translator loads its rule base by reading files of rules as if they
were concatenated with the sources to be translated. The rule-specification
syntax is abysmal, primarily  because it was chosen to minimize the amount 
of time I spent struggling with shift-reduce conflicts from yacc, rather than
making the rules intelligible to users. Smalltalk's formal grammar seemed
unreasonably difficult for yacc to swallow, and I suspect the problem may
lie in some mistake I've made in translating Smalltalk-80 syntax diagrams
into yacc specifications.
.np
The program contains extensive provisions for reporting its cogitations in
type inferencing. The various error, warning, logging, and debugging messages
need to be tuned for greater utility.
.np
The code was based on an as yet unreleased libary (phylum) called "Substrate",
which supports features that are not yet in our standard product set, like
Blocks, Coroutining, and exception handling.  I made a fast editing pass
to remove any dependencies on these nonstandard library features. I also 
added a file, Substrate.h, that defines stylistic conventions that I adhere
to in all my work. See USE, IMPORT, EXPORT, etc in the sources.
.pp
The preceeding problems are superficial and easily repaired. The following
ones are somewhat more substantial in that they involve design work in 
addition to coding work.
.np
The type inferencing machinery infers types of newly-encountered (unknown)
messages and variables by seeing how they are combined with variables and
messages whose types are known apriori or else determined earlier through
inferencing.  The only types that are known apriori are literals like 1,
2.3, or 'string'. This generally provides insufficient typing information
from which to infer anything useful, so you should generally provide variable
rules to pin down types for key instance variables and method arguments
You do this with rules that state, in effect, that `the type of the Smalltalk
variable named foo is int, and the variable is called foobar in Objective-C'.
Presently rules have global scope. If different Smalltalk classes use the
name, foo, in ways that should be translated differently, different rule
sets must be provided manually to the translator. Creating and managing 
these application-specific rules sets adds to the translation effort and 
tends to make rules non-reusable across translations. The rules should be
organized with a scoping mechanism, ideally one based on inheritance.
.np
The inferencing logic is ad-hoc and quite possibly slow. However the main
bottleneck seems to be loading the rule-base; translation speed has never 
been a real problem. Inferencing is presently deductive, and a more inductive
scheme based on both forwards and backwards reasoning might produce higher
quality translations. In other words, the translation of a given message
expression is determined exclusively by whatever information can be inferred
about the types of the receiver and arguments to that message (forward 
reasoning). Backward reasoning would also consider how the results of the
expression are used in other expressions.
.np
Producer does not presently handle non-trivial uses of Blocks correctly; ie.
Block expressions that cannot be translated directly into C conditional
expressions like if, while, or for, which Producer handles just fine already.
Nearly all occurrences of Smalltalk-80 Blocks could be handled without
changing the Objective-C language by adding a trivially simple Block class
to the library. A named instance variable holds a pointer to a static function
and indexed instance variables hold \fIcopies of\fP any variables that the
block accesses in the instantiation site\**. This copy could be taken
entirely automatically by copying the instantiation site's stack frame.
However I prefer to have more control over space than that. So I've been
using a scheme that requires the programmer (and someday the compiler) to
specify which variables are really accessed by the block as arguments to
the message that instantiates the block; like this
.(C
 ... { 
	IMPORT void aStaticFunction();
    id var1 = something, var2 = something;
	aBlock = [Block function:aStaticFunction args:2, var1, var2];
	[anyObject do:aBlock];
	...
 }
 LOCAL void aStaticFunction(instantiationSiteVariables, value1, value2)
	struct { id var1, var2; } *instantiationSiteVariables;
	id value1, value2;
 {
	if ([instantiationSiteVariables->var1 someMessage])
		...
 }
.)C
.ip
The block will call the function when anyObject sends the block one of several
evaluation messages (value:arg1 or value:arg1 value:arg2 or ...). The first
argument is a \fIpointer\fP to block's copy of the instantiation site's 
variables. The trailing arguments contain the arguments that the invocation 
site passed in the value: message.  I've used this approach extensively by
writing the static functions by hand, and am trying to get our staff to 
extend the language to provide some kind of language-level support to make
the syntax simpler.  This approach could be, but has not yet been, taken by
Producer.
.(f
\** In Smalltalk-80, the block seems to have access to the instantiation
site's variables, so that the block can change variables in the instantiation
site. In Objective-C the block receives a copy of the variables and cannot
use them to communicate with the instantiation site. I believe that this is
the sole functional difference between the two schemes.
.)f
.pp
The inferencing machinery's primary current virtue is that it can be made
to work for selected test cases. It leaves lots to be desired. Call me
if you decide to extend it so that I can prevent unnecessary duplication of
effort.

.H "About the distribution"
.pp
The top level of the distribution consists of
.(C
total 88
-rw-r--r--  1 cox           181 Jun 22 14:32 Makefile
-rw-r--r--  1 cox         26592 Jun 22 14:30 README
drwxr-xr-x  2 cox           512 Jun 22 14:19 example
-rw-r--r--  1 cox           166 Jun 16 13:18 log
-rw-r--r--  1 cox           997 Jun 15 11:09 mac.me
-rw-r--r--  1 cox         26751 Jun 15 11:02 producer.me
-rw-r--r--  1 cox         21444 Jun 22 14:29 readme.me
drwxr-xr-x  2 cox           512 Jun 12 10:22 rules
drwxr-xr-x  2 cox          3072 Jun 22 14:31 src
.)C
The Makefile governs formatting of the two documents; this README (from 
readme.me) and the draft of the OOPSLA-87 paper (from Producer.me). The 
mac.me file contains text formatting macros that are common to both papers;
used like this:
.(C
nroff -me mac.me Producer.me >Producer.f
.)C
.pp
The rules directory contains a single file, generic.ru, that represents a 
first pass at an application-independent rules base. This set of rules 
translate Smalltalk to the conventions used in my prototype version of 
the user interface library.
.pp
For example, it translates Smalltalk Integer operations to C int operations,
and it translates Smalltalk Point operations to C macros that manage points 
as type PT; a pair of 16-bit coordinates in a 32-bit C int.  For example,
pt(x,y) invokes a C macro that trims and shifts two ints, x and y, to fit
side by side in a 32-bit integer, ptPlus(p,q) invokes a macro that computes 
the vector sum of two points, p and q, etc.
.(C
rules:
total 35
-rw-r--r--  1 cox         35567 Jun 12 10:22 generic.ru
.)C
.pp
The src directory contains a fragment from the video animation program that
appears at the end of the Smalltalk-80 video tape. BounceInBoxNode.st is
the Smalltalk-80 source file, animation.ru contains the application-specific
rule set, BounceInBoxNode.m is the translated version built by Producer as
invoked by Makefile\**.
.(f
\** The full source for the animation program is not provided. My copyright
paranoia argued against providing even this fragment.
.)f
.(C
example:
total 7
-rw-r--r--  1 cox          1730 Jun 16 10:24 BounceInBoxNode.m
-rw-r--r--  1 cox           868 Jun 16 10:18 BounceInBoxNode.st
-rw-r--r--  1 cox           394 Jun 16 10:20 Makefile
-rw-r--r--  1 cox          2178 Jun 16 10:18 animation.ru
-rw-r--r--  1 cox           185 Jun 16 10:24 log
-rw-r--r--  1 cox           239 Jun 16 10:18 st80.h
.)C
.pp
The log file records the results of the translation session. The syntax
error is innocuous, the result of the beforementioned problem in the grammar
in handling '!' delimiters.
.(C
Producer -c ../rules/generic.ru animation.ru BounceInBoxNode.st >BounceInBoxNode.m
error 7:BounceInBoxNode.st: tegory:'Graphics-Animation'!! : syntax error
*** Error code 1 (ignored)
.)C
.pp
The src directory contains the sources for Producer, with its own Makefile.
The Substrate.h header file, which is automatically included by the
Producer.h header file, is technically a part of a internal lower level
library, Substrate, on which Producer was originally developed. Substrate.h
was copied and changed superficially so that Producer compiles correctly
without the Substrate library.
.(C
src:
total 70
-rw-r--r--  1 cox           483 Jun 12 10:21 AbstractTranslation.m
-rw-r--r--  1 cox           282 Jun 12 10:21 ArgumentList.m
-rw-r--r--  1 cox           897 Jun 12 10:21 Block.m
-rw-r--r--  1 cox           143 Jun 12 10:21 CharConstant.m
-rw-r--r--  1 cox          2205 Jun 12 10:21 Class.m
-rw-r--r--  1 cox           630 Jun 12 10:21 Comment.m
-rw-r--r--  1 cox           176 Jun 12 10:21 Constant.m
-rw-r--r--  1 cox          2032 Jun 12 10:21 Expr.m
-rw-r--r--  1 cox          1243 Jun 12 10:21 FunctionTranslation.m
-rw-r--r--  1 cox          1484 Jun 12 10:21 Identifier.m
-rw-r--r--  1 cox          1248 Jun 12 10:21 IdentifierTranslation.m
-rw-r--r--  1 cox           105 Jun 12 10:21 List.m
-rw-r--r--  1 cox          1985 Jun 15 11:55 METHODDECLS.m
-rw-r--r--  1 cox          1384 Jun 15 11:51 Makefile
-rw-r--r--  1 cox          4302 Jun 12 10:21 Method.m
-rw-r--r--  1 cox          3136 Jun 12 10:21 Msg.m
-rw-r--r--  1 cox           583 Jun 12 10:21 MsgArgPattern.m
-rw-r--r--  1 cox           828 Jun 12 10:21 MsgNamePattern.m
-rw-r--r--  1 cox          1280 Jun 12 10:21 MsgTranslation.m
-rw-r--r--  1 cox           775 Jun 12 10:21 MsgTranslator.m
-rw-r--r--  1 cox          1868 Jun 12 10:21 Node.m
-rw-r--r--  1 cox           229 Jun 12 10:21 NumberConstant.m
-rw-r--r--  1 cox          1402 Jun 15 11:27 Producer.h
-rw-r--r--  1 cox           306 Jun 12 10:21 Return.m
-rw-r--r--  1 cox           825 Jun 12 10:21 Scope.m
-rw-r--r--  1 cox          3157 Jun 12 10:21 Selector.m
-rw-r--r--  1 cox           253 Jun 12 10:21 SelectorConstant.m
-rw-r--r--  1 cox           457 Jun 12 10:21 StArray.m
-rw-r--r--  1 cox           492 Jun 12 10:21 Stmt.m
-rw-r--r--  1 cox           381 Jun 12 10:21 StringConstant.m
-rw-r--r--  1 cox          1268 Jun 12 10:21 StringTranslation.m
-rw-r--r--  1 cox          2140 Jun 15 11:38 Substrate.h
-rw-r--r--  1 cox          1405 Jun 15 11:53 Symbol.m
-rw-r--r--  1 cox           452 Jun 12 10:21 Template.m
-rw-r--r--  1 cox           901 Jun 12 10:21 Type.m
-rw-r--r--  1 cox          1800 Jun 12 10:21 design.me
-rw-r--r--  1 cox          3271 Jun 12 10:21 gen.m
-rw-r--r--  1 cox          9007 Jun 12 10:21 gram.y
-rw-r--r--  1 cox          3601 Jun 12 10:21 lex.l
-rw-r--r--  1 cox          2212 Jun 12 10:21 main.m
-rw-r--r--  1 cox           260 Jun 12 10:21 st80.h
-rw-r--r--  1 cox           259 Jun 15 11:59 y.tab.h
.)C
.pp
The files are exactly as I left them nearly a year and a half ago, except 
for:
.np
The addition of this README document. An early draft of the OOPSLA-87
paper, sadly prior to Kurt Schmucker's improvements, is in Producer.me.
.np
One recompilation pass to remove any obvious dependencies on my private
Substrate library and to verify that Producer compiles and runs correctly 
on the standard Foundation library. I tested the changes by verifing that 
the Makefile in the example directory ran to completion, but this is hardly
an ironclad guarantee. 

.H "Using Producer"
.pp
Flags controlling the translation process, source files, and rules files
are provided on the command line and are processed in the order they appear.
The flags are\**
.(f
\** I'm working from memory about what these flags mean. Some may
be nonfunctional:
.)f
.ip -d:
Enable debugging functions (dbg()) scattered throughout the code. Seldom
useful.
.ip -m:
Enables the Objective-C Foundation library message tracing feature. Seldom
useful in Producer.
.ip -a:
Enables the Objective-C Foundation library allocation tracing feature. Seldom
useful in Producer.
.ip -l:
Enables printing of each lexical token as produced by lex. Useful only for
debugging lex.l.
.ip -g:
Enables automatic redirection of each class into a separate file based
on the class name parsed from the input file. Automatically puts class
Foobar into file Foobar.m. 
.(q
CAREFUL! This puts at risk other files whose name might coincide with
a Smalltalk-80 class name!
.)q
.ip -s:
Generate Smalltalk-80 sources in the output file as Objective-C comments
(the default).
.ip -c:
Don't generate Smalltalk-80 sources in the output file.
.ip -i:
Generate information that was thought at one time to be useful when 
debugging rules.
.ip -M:
Send storeOn: to the message rule dictionary just before terminating 
as a debugging aid.
.ip -I:
Send storeOn: to the variable rule dictionary just before terminating 
as a debugging aid.
.pp
Typically, the generic rules in rules/generic.ru is specified first, then 
any application-specific rules, then a single Smalltalk-80 source file.
Unless -g is set, the translated output appears on stdout. The various
creaks, groans and mumbles that can be elicited about the translation 
process itself appear on stderr.
.pp
For the syntax for writing new rules, refer to the examples in generic.ru
and animation.ru, and if necessary, the rules section of the grammar in gram.y. 
.pp
And good luck! Let me know how you fare...
\Rogue\Monster\
else
  echo "will not over write ./readme.me"
fi
echo "Finished archive 1 of 5"
exit
----
Dieter H. Zebbedies ('dee-ter  ayech  'zeb-ed-eez)
 Zebb-Hoff Mach. Tool's Automated Manufacturing Project Cleveland, OH
 (USnail): 9535 Clinton Rd, Cleveland, OH 44144 (+216 631 6100) (+216 741-5994)
 (UUCP): ...{decvax,sun,cbosgd}!cwruecmp!zhmti!dieter
 (CSNET/ARPA/BITNET): dieter@CWRU.Ewil

dietz@zhmti.UUCP (Dieter H. Zebbedies) (08/20/87)

"Producer", A package to translate Smalltalk-80 code to your favorite
object oriented language, Objective-C.

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -d ./example`
then
  mkdir ./example
  echo "mkdir ./example"
fi
if `test ! -s ./example/Makefile`
then
echo "writting ./example/Makefile"
cat > ./example/Makefile << '\Rogue\Monster\'
O= BounceInBoxNode.o 
M= BounceInBoxNode.m 
S= BounceInBoxNode.st 
.SUFFIXES:
.SUFFIXES: .m .st .o .i
P=../src/producer -c
R=../rules/generic.ru animation.ru
X=objcc -c -I/u/cox/ui
all: rm src
rm:					; rm -f $M
src: $M
obj: $O
stvd.a:	$O			; ar ruv stvd.a $*
.st.o:				; $P $R $< >$*.m && $X $*.m
.st.m:				; -$P $R $< >$*.m
.st.i:				; $P -i $R $< >$*.i 2>&1
.m.o:				; $X $*.m
wc:					; wc $S
clean:				; rm -f *.[mcoi] log core
\Rogue\Monster\
else
  echo "will not over write ./example/Makefile"
fi
if `test ! -s ./example/BounceInBoxNode.st`
then
echo "writting ./example/BounceInBoxNode.st"
cat > ./example/BounceInBoxNode.st << '\Rogue\Monster\'
MovingNode subclass: #BounceInBoxNode
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Graphics-Animation'!

!BounceInBoxNode methodsFor: 'display'!
displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle rule: 
	ruleInteger mask: aForm
	| relLoc |
 	super displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle 
		rule: ruleInteger mask: aForm.
	relLoc _ location + clipRectangle origin.
	(velocity x < 0 and: [relLoc x < clipRectangle left])
		ifTrue: [velocity _ velocity*(-1@1)].
	(velocity x > 0 and: [(relLoc x+contents width) > clipRectangle right])
		ifTrue: [velocity _ velocity*(-1@1)].
	(velocity y < 0 and: [relLoc y < clipRectangle top])
		ifTrue: [velocity _ velocity*(1@-1)].
	(velocity y > 0 and: [(relLoc y+contents height) > clipRectangle bottom]
)
		ifTrue: [velocity _ velocity*(1@-1)].
! !

\Rogue\Monster\
else
  echo "will not over write ./example/BounceInBoxNode.st"
fi
if `test ! -s ./example/st80.h`
then
echo "writting ./example/st80.h"
cat > ./example/st80.h << '\Rogue\Monster\'
// Collecting.h:
#ifndef VIDEOANIMATION_H
#define VIDEOANIMATION_H
#	include "DisplayObjects.h"

#	ifdef OBJC_COX
#	define CATEGORIES()
#	else
#	define CATEGORIES() (VideoAnimation, DisplayObjects, Collecting, Primitive)
#	endif

#endif


\Rogue\Monster\
else
  echo "will not over write ./example/st80.h"
fi
if `test ! -s ./example/animation.ru`
then
echo "writting ./example/animation.ru"
cat > ./example/animation.ru << '\Rogue\Monster\'
{ # BounceInBoxNode (id) BounceInBoxNode }
{ # DisplayObject (id) DisplayObject }
{ # EvaluationNode (id) EvaluationNode }
{ # MovingNode (id) MovingNode }
{ # PositionNode (id) PositionNode }
{ # SequenceNode (id) SequenceNode }
{ # SuperpositionNode (id) SuperpositionNode }
{ # WindowNode (id) WindowNode }
{ # aBlock (id) aBlock }
{ # aCollection (id) aCollection }
{ # aDisplayPoint (PT) aDisplayPoint }
{ # aForm (id) aForm }
{ # boundingBox (id) boundingBox }
{ # c (id) aCollection }
{ # clipRect (id) clipRect }
{ # clipRectangle (id) clipRectangle }
{ # contents (id) contents }
{ # destForm (id) destForm }
{ # evalBlock (id) evalBlock }
{ # index (int) index }
{ # l (PT) locationPoint }
{ # location (PT) location }
{ # node (id) node }
{ # position (PT) position }
{ # relLoc (PT) relLoc }
{ # ruleInteger (int) ruleInteger }
{ # subNodes (id) subNodes }
{ # v (PT) velocityPoint }
{ # velocity (PT) velocity }
{ # window (id) window }

{ (id)displayOn:(id) at:(PT) clippingBox:(id) rule:(int) mask:(id) #
	(id) [displayOn:%1 at:(PT)%2 clipBy:%3 rule:(int)%4 mask:%5] }
{ # [(id)at:(PT)pt] }
{ # [(id)contents:(id)a location:(PT)b ] }
{ # (id)[fixTemps] }
{ # (id)[setBlock:(id)a] }
{ # (id)[setContents:(id)a location:(PT)b] }
{ # (id)[setSubNodes:(id)a ] }
{ # (id)[setVelocity:(PT)a ] }
{ (id)setNodes:(id) index:(int) # (id)[setNodes:(id)nodeCollection index:(int)anInteger] }
{ (id)subNodes:(id) index:(int) # (id)[subNodes:(id)aCollection index:(int)anInteger] }

{ # (BOOL)[anyButtonPressed] }
{ # (id)[block:(BLOCK)aBlock ] }
{ # (id)[contents:(id)aForm location:(PT)aPoint velocity:(PT)velocityPoint ] }
{ # (id)[displayView] }
{ # (id)[extent:(PT)anExtent fromArray:anArray offset:(PT)aPoint ] }
{ # (id)[model:(id)aModel ] }
{ # (PT)[mousePoint] }
{ # (RULE)[over] }
{ (id)pi # (float)'3.414' }
{ # (id)[release] }
{ # (id)[run:(id)aWindowNode ] }
{ # (id)[setWindow:(id)aWindow contents:(id)aCollection ] }
{ # (id)[spiral:(float)anAngle] }
{ # (id)[subNodes:(id)aNode ] }
{ # (id)[window:(id)aWindow contents:(id)aCollection ] }
{ (id)with:(id) with:(id) with:(id) # (id)'[%0 with:3, %1, %2, %3]' }
{ # n (int) n }
{ # (int)[collect:(BLOCK)aBlock ] }
\Rogue\Monster\
else
  echo "will not over write ./example/animation.ru"
fi
if `test ! -s ./example/BounceInBoxNode.m`
then
echo "writting ./example/BounceInBoxNode.m"
cat > ./example/BounceInBoxNode.m << '\Rogue\Monster\'
// // MovingNode subclass: #BounceInBoxNode
// 	instanceVariableNames: ''
// 	classVariableNames: ''
// 	poolDictionaries: ''
// 	category: 'Graphics-Animation'!

#include "st80.h"
= BounceInBoxNode:MovingNode CATEGORIES(){
}
// 
// !BounceInBoxNode methodsFor: 'display'!
// displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle rule: 
// 	ruleInteger mask: aForm
// 	| relLoc |
//  	super displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle 
// 		rule: ruleInteger mask: aForm.
// 	relLoc _ location + clipRectangle origin.
// 	(velocity x < 0 and: [relLoc x < clipRectangle left])
// 		ifTrue: [velocity _ velocity*(-1@1)].
// 	(velocity x > 0 and: [(relLoc x+contents width) > clipRectangle right])
// 		ifTrue: [velocity _ velocity*(-1@1)].
// 	(velocity y < 0 and: [relLoc y < clipRectangle top])
// 		ifTrue: [velocity _ velocity*(1@-1)].
// 	(velocity y > 0 and: [(relLoc y+contents height) > clipRectangle bottom]
// )
// 		ifTrue: [velocity _ velocity*(1@-1)].
// ! !

- displayOn:destForm at:(PT)aDisplayPoint clippingBox:clipRectangle rule:(int)ruleInteger mask:aForm {
	PT relLoc;
	[super displayOn:destForm at:aDisplayPoint clipBy:clipRectangle rule:ruleInteger mask:aForm];
	relLoc = ptPlus(location, [clipRectangle origin]);
	if (ptX(velocity) < 0 && ptX(relLoc) < [clipRectangle left]) velocity = ptTimes(velocity, pt(-1,1))if (ptX(velocity) > 0 && ptX(relLoc) + [contents width] > [clipRectangle right]) velocity = ptTimes(velocity, pt(-1,1))if (ptY(velocity) < 0 && ptY(relLoc)


 < [clipRectangle top]) velocity = ptTimes(velocity, pt(1,-1))if (ptY(velocity) > 0 && ptY(relLoc) + [contents height] > [clipRectangle bottom]) velocity = ptTimes(velocity, pt(1,-1))return self;
}
// 
// \Rogue\Monster\
else
  echo "will not over write ./example/BounceInBoxNode.m"
fi
if `test ! -s ./log`
then
echo "writting ./log"
cat > ./log << '\Rogue\Monster\'
itroff -me mac.me doc.me
.C 0-1 ""
.H0 0-1 "Provisos"
.H0 0-1 "How it works"
.H0 0-2 "Status"
.H0 0-3 "What's in this distribution"
.H0 0-5 "Usage"
------ make doc.i
\Rogue\Monster\
else
  echo "will not over write ./log"
fi
if `test ! -s ./producer.me`
then
echo "writting ./producer.me"
cat > ./producer.me << '\Rogue\Monster\'
.tp
.po .5i
.ll 7i
.(l C
\fB\s14Producer\s0\fP

\fIFrom the Prototyping Laboratory to the Production Line
Translating Smalltalk-80 Applications to Objective-C\fP

Brad Cox, Ph.D.
Productivity Products International
Sandy Hook, CT 06497
(203) 426 1875

For presentation at OOPSLA/86
.)C
.(q
.hl
.ce
\fIAbstract\fP
.sp
This paper proposes that source to source translation tools could provide
a way of integrating the strengths of production programming environments
like C/Unix with rapid prototyping environments like Smalltalk-80 into a
comprehensive hybrid environment that spans more of the software development
life-spiral than ever before. It describes a tool-assisted process for
translating Smalltalk-80 programs into Objective-C, and shows how the
tool is used in practice.
.hl
.)q
.he 'Producer''
.fo 'Productivity Products International'Page %'\*(td'
.(f
\fIObjective-C, Software-IC, Vici\fP and \fIPPI\fP are trademarks of 
Productivity Products International.
.)f
.(f
\fISmalltalk-80\fP is a trademark of Xerox Corporation.
.)f
.(f
\fIUnix\fP is a trademark of AT&T.
.)f
.pp
Smalltalk-80 and C/Unix are very different tools that are optimized for 
different jobs at opposite ends of the process for transforming raw ideas
into commercial software products. To use an analogy from automobile 
manufacturing, Smalltalk-80 is at its best in the design shop for building 
prototypes from which next year's model can be visualized, and C/Unix are at
their best on the production line for building cost-effective implementations 
once the design has been proven through prototyping.
.pp
However it is becoming increasingly harder to maintain a strict separation
between prototyping and production. Many production systems, particularly
in CAD and office automation, are providing features, like iconic user 
interfaces, that grew up in prototyping environments and which depend 
on experimentation and tuning for good human factors.  This kind of tuning
is far easier in prototyping languages like Smalltalk-80, because machine
resources can be spent lavishly on pervasive productivity aids like automatic
garbage collection, and because the tools are tightly coupled to the system
being constructed.
.pp
However the C/Unix community has historically favored a non-integrated 
approach that keeps the product separate from the tools, and they commonly 
exploit special purpose languages to amplify C's basic capabilities; 
i.e. \fIyacc\fP for building parsers, \fIlex\fP for building lexical
analyzers, \fItroff\fP for formating documents, \fImake\fP for controlling
compilations, \fIadb\fP or \fIdbx\fP for debugging, and many others\**.
So why not treat Smalltalk-80 as a special purpose tool for rapid 
prototyping and ultimately translate the prototypes into C for
production? This could eliminate the cradle to grave committment problem
that has hindered Smalltalk's acceptance to date, and would integrate 
the strengths of the two approaches into a comprehensive hybrid software 
development environment.
.(f
\** Unix Programmers Manual. In particular see \fILex - A Lexical Analyzer 
Generator\fP, and \fIYacc - Yet Another Compiler Compiler\fP. Also see \fILR
Parsing\fP, Aho and Johnson, Computing Surveys, June, 1974.
.)f
.pp
This article describes a tool-assisted process for translating Smalltalk-80
applications into C language. The routine parts of the process are handled
by a translation tool, \fIproducer\fP, which translates Smalltalk-80 code into
Objective-C, an object-oriented extention to C language.  Obviously, it is
not realistic to expect any tool to turn arbitrary half-baked prototypes
into polished software products automatically. Nor can static analysis make
perfectly accurate predictions about a program's dynamic behavior, such
as the specific type a polymorphic variable will hold at run time or when
it is safe to release storage that may be multiply referenced. This 
information is not available in the text of a Smalltalk program and 
deriving it by static analysis is a truly hard (NP-complete) problem. 
This work sidesteps these problems by keeping the programmer involved in
the translation process.
.pp
Translating code between languages as different as these is like designing
a bridge. Although bridge builders often use generic tools and components,
each bridge is custom designed to fit within a larger system of expressways,
access roads, and approach ramps.  No part is designed in isolation, but in 
combination to reduce the overall cost of the project.  Producer is not a
bridge, but a component from which bridges can be assembled.  It need not
solve the general problem of translating arbitrary Smalltalk-80 program into
C with guaranteed reliablity, since the programmer can help by changing the
source and target environments, by guiding the translation, or even by 
repairing translation errors by hand. 

.H "Background"
This work was made feasible by several other PPI projects, all directed at
the same goal; adapting concepts and tools that have been proven in the
prototyping community for use in production programming.  The foundation
is Objective-C language, which is implemented by a compiler that translates
object-oriented constructs of Smalltalk-80 into expressions that can compiled
by any C compiler.  The same language is also available in \fIVici\fP, an 
interpreter that allows classes and ordinary C code to be developed, tested,
and changed interactively by eliminating the usual edit, compile, link, and
test cycle.
.(f
\** \fIObject-oriented Programming, An Evolutionary Approach\fP, Brad Cox,
Addison Wesley, 1986.
.)f
.pp
Both products make object-oriented programming available to production
programmers. This make it possible for them to cooperate in building and
reusing large libaries of pretested, documented classes that PPI 
calls \fISoftware-ICs\fP to dramatize important parallels between 
object-oriented programming and the invention of the integrated circuit
chip, two technologies for packaging the efforts of suppliers for reuse
by consumers. This provides the crucial missing element that has until 
now prevented software developers from obtaining the explosive growth
in productivity that hardware developers achieve routinely.
.pp
Several such libraries have been implemented.  Classes similar to Smalltalk's
lower-level classes (Arrays, Collections, etc) have long been available\**, 
.(f
\** \fISoftware-IC Specification Sheets\fP, Objective-C Programmers 
Reference Manual; PPI.
.)f
and a compatible library of user interface Software-ICs has recently been 
developed in a form that is portable across the windowing environments of 
most engineering workstations\**.
.(f
\** \fIObject-oriented Programming and Iconic User Interfaces\fP, 
Bill Hunt (Hewlett Packard) and Brad Cox (PPI), Byte Magazine, August 1986.
.)f
Other projects\** have developed additional features of the Smalltalk 
substrate, including an (optional) automatic garbage collector.
.(f
\** Unpublished; Frank Parish (Hewlett Packard) and Alan Watt (PPI).
.)f
.pp
These libraries provide the substrate needed to build an eventual Unix-based
environment that has many Smalltalk-like features such as an interactive
browser for developing, describing, learning about, and using large 
collections of ordinary C code and/or Software-ICs.  Although this will 
make programming with C and/or Objective-C more productive, it is by design
an environment for production programming and will not eliminate the need
for Smalltalk-80 as a specialized prototyping environment.

.H "Prototyping versus Production Programming"
When a line of Smalltalk-80 code works correctly, it has successfully met
several layers of requirements imposed by the Smalltalk-80 language, its
run-time environment, and the programmer who wrote it. In transforming it
into Objective-C code, it must meet similar requirements of the target
language, environment, and programmer.  These requirement layers amount
to progressively higher hurdles over which the code must be carried:
.np
Syntactic: The first hurdle involves converting syntactically valid 
Smalltalk-80 statements to syntactically valid Objective-C statements.
This can be done with simple tools that are concerned only the syntax of
the two programming \fIlanguages\fP.
.np
Semantic: The second hurdle involves preserving the meaning of the code,
when executed in the Smalltalk-80 environment, when it has been transformed
for execution in the Objective-C environment. This requires knowledge of
the two \fIenvironments\fP.
.np
Intentional: This is a coined term that signifies transforming code that
reflects the intentions of the prototype builder to meet the intentions of
one building a system for production.  This requires knowledge of the
intentions of the \fIprogrammers\fP themselves, or more practically,
their direct involvement in one or more stages of the translation.
.pp
Since Objective-C's object-oriented capabilities were modeled directly 
after Smalltalk's, message expressions can be translated one for one
into Objective-C messages.  However this is of so little practical interest
that it has never been attempted.  After passing each of the Smalltalk
classes through such a translator, implementing the entire Smalltalk 
virtual machine, and installing an automatic garbage collector, the 
translated code would have the vices of both languages and the virtues
of neither.  It would run no faster and it would be just as incompatible
with other Unix tools.  To be of practical interest, the translation 
process must also provide a way of providing correctness at each one of
the other levels; syntactic, semantic, and intentional. This is hard to
do automatically, but relatively easy if the programmer is involved 
in the translation.
.pp
For example, a Smalltalk-80 prototype might conceivably compose statements
as data and compile them for execution on the fly. Although Objective-C is
designed primarily as a language to be compiled in advance of program
execution, several options are available for translating these prototypes. 
The programmer might choose to incorporate \fIVici\fP into the target system,
as this would reduce labor costs at the source side. Or he might decide
to modify the prototype to avoid this feature to provide better execution 
speed on the target side.  Similarly, Smalltalk-80 implements low-level 
types like points (coordinates) as dynamically-bound objects, and this 
allows higher level code to be independent of whether points are represented
as integers or floating point numbers. Objective-C's user interface library 
removes this freedom in favor of greater machine efficiency. Should a
Smalltalk program rely on polymorphic points, its programmer could choose 
between developing a different user interface library that does use
polymorphic points, changing the prototype to avoid the problem, or
accepting a certain proportion of errors in the translation to be repaired
by hand. No translation is impossible; some just cost more than others.

.H "Producer"
The automatic part of a translation involves a tool named `producer'.  Producer
is basically a Smalltalk-80 compiler that generates Objective-C code, but it
differs from most compilers in that it can also accept additional information 
to guide how code will be generated. If this information is not provided,
producer translates Smalltalk-80 statements into Objective-C code in a
straightforward, non-rigorous manner. For example, it will translate each
Smalltalk message expression to a syntactically equivalent Objective-C
expression, but it translates literal constants into primitive C types and
does nothing special to ensure that the code generated from Smalltalk
block expressions is syntactically legal.
.pp
Producer is implemented in Objective-C and other Unix tools.  Its lexical
analyzer, written in \fIlex\fP, composes characters into tokens and delivers 
them to the parser, written in \fIyacc\fP. The parser recognizes syntactic 
components of the Smalltalk-80 language and executes Objective-C statements 
that build a syntax tree bottom-up as instances of syntactic classes like 
Method, Message, and Identifier. Some of these classes eliminate minor 
syntactic incompatibilities by rewriting the tree. For example, the Expr
(expression) class eliminates cascaded message expressions by adding temporary
variables to the nearest enclosing scope and builds the tree as a sequence 
of simple message expressions.
.pp
As a refinement, the lexer accumulates every token in a list that can be
printed just before the code generation pass as an Objective-C comment.
This preserves the original Smalltalk statements and comments in the 
generated code.  Code generation begins when the grammar recognizes a 
method or class declaration and sends the top of the syntax tree (an
instance of Method or Class) the message, \fIgen\fP. The method class 
implements this message by first requesting its subnodes to determine 
their types, a recursive process that involves rule processing and type
inferencing.  Then it begins code generation by generating tokens that
Objective-C will recognize as a method declaration and requests its
subnodes to do likewise.
.pp
In principle, translation rules could be attached to any syntactic class,
but currently only the Method, Message, and Identifier classes provide the
necessary hooks. Rules are typically provided in separate files that are 
read before the source to be translated and are parsed by special grammar
productions.  Identifier rules declare the type of specific identifiers and
can optionally assign a new spelling for each identifier in the generated
code.  Most often, declarations are provided only for instance variables 
and method arguments since these generally provide sufficient information 
that types of other variables (method and block local variables) can be
inferred from how they are used.
.pp
The Message class provides a more elaborate kind of hook that allows more
than one translation to be associated with each selector (a similar hook
exists in the Method class).  The specific translation for such messages
is chosen according to typing information that can be derived from several 
sources. The type of literal constants is derived automatically, and types 
of variables are determined by declarative rules provided by the programmer 
and also by type inferencing rules that are built into producer. The argument
or receiver of one message is often another message expression, whose type
depends on the type of its arguments, and so on recursively.  Currently,
translations for messages are chosen according to the selector and the
type of the message's receiver and arguments (forward reasoning), but this 
may be extended to also consider how the result of the translated message 
is used (backward reasoning).
.pp
Blocks are translated via the usual message translation rules, triggered 
by arguments of type BLOCK. While many blocks can be translated as
as C conditional statements and expressions (if, for, while, etc),
elaborate blocks cannot be translated in this way.  If experience
demonstrates the need, more ambitious translations can be added,
such as rewriting block bodies as C function bodies.

.H "Results"
The current implementation of producer consists of 1804 lines of Objective-C
code, 223 of which are also processed by yacc and 105 by lex. Only three
man-weeks have been invested, two in developing producer and producing
the results shown here and the other in writing this paper. To date,
translations have been verified by desk checking, but it should be possible
to show translated applications in operation by the time this paper is
presented.
.pp
The group that developed Smalltalk-80 has produced a video tape that Xerox
uses to promote sales of Smalltalk systems. The tape concludes with a 
animation of three shapes bouncing in a rectangular enclosure; a circle, a
rotating star, and a square that shows the area near the cursor. The tape
was filmed on a Dorado, a relatively powerful computer, but the same program
is also available on less expensive machines like the Tektronix Artificial 
Intelligence Workstation, which is based on the same Motorola 68010 chip
as the Sun workstations used in most of our work. This program was chosen
to demonstrate the translation process in action.
.pp
The animation application involves 236 lines of Smalltalk code. Its source
environment is the standard Smalltalk-80 environment, and the goal is to
translate it to run in a target environment that is defined by the 
Objective-C user interface library.  This environment involves three 
layers of abstraction:
.np
The substrate layer includes the primitive data types of the C compiler,
Unix, and the proprietary windowing environments of diverse workstation
vendors, and is therefore not part of the library. The library confines
itself to building user interfaces to run in virtual terminals provided
by the windowing environment.
.np
The DisplayObjects level duplicates the functionality of the Smalltalk 
graphics environment insofar as this has been described publically\**.
It provides a Form class whose instances hold rectangular raster images 
in memory, a DisplayScreen class (a subclass of Form) whose instances
provide an object-oriented interface to a virtual terminal, and a number
of specialized subclasses like InfiniteForm, OpaqueForm, Cursor, and Sensor.
The classes and methods in this library are essentially identical to 
Smalltalk's, but they assume that objects below the level of class Rectangle
are primitive types of the substrate; e.g. Points, Numbers, Booleans, and 
so forth.
.(f
\** Goldberg and Robson's \fISmalltalk-80: The language and its
implementation\fP
.)f
.np
The UserInterface level is similar to, but does not duplicate, the Smalltalk
Interface-Framework classes that implement the model/view/controller (MVC) user 
interface paradigm. This level of the library is not compatible, partially
because MVC seems unnecessarily complicated, but primarily to avoid any
appearance of violating Xerox copyright protection on concepts that are
documented only in Smalltalk-80 sources. Unless this restriction can be
lifted, the only recourse may be to code prototypes to use a new Smalltalk
library written to parallel the Objective-C library.
.pp
The DisplayObjects level also defines a statically typed implementation 
of the Point (coordinate) class as a collection of C macros and functions:
.(C
typedef struct { short x, y; } PT;\**	// aPoint
.)C
This trades the advantages of polymorphic points to gain machine efficiency 
and compatibility with other tools in the target environment; particularly 
vendor-supplied windowing environments. And managing low level objects like
points by value instead of by reference reduces the need for automatic
garbage collection significantly.
.(f
\** Since many C compilers implement structure assignment inefficiently,
the library coerces this type such that points are passed to and returned
from functions as integers rather than as structures. This is why the x
portion of aPoint is accessed as X(aPoint) rather than aPoint.x.
.)f
.pp
The translation for this application involves 796 lines of rules, 735 of
which are generic rules that describe low-level Smalltalk objects (Booleans,
Numbers, etc) and 61 of which are application-specific rules that describe
types in the animation application. The following is a typical translation:
.(C
// MovingNode subclass: #BounceInBoxNode
//	instanceVariableNames: ''
//	classVariableNames: ''
//	poolDictionaries: ''
//	category: 'Graphics-Animation'!

#include "st80.h"
= BounceInBoxNode:MovingNode CATEGORIES() { }

// !BounceInBoxNode methodsFor: 'display'!
// displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle rule: 
//	ruleInteger mask: aForm
//	| relLoc |
//	super displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle 
//		rule: ruleInteger mask: aForm.
//	relLoc \(<- location + clipRectangle origin.
//	(velocity x < 0 and: [relLoc x < clipRectangle left])
//		ifTrue: [velocity \(<- velocity*(-1@1)].
//	(velocity x > 0 and: [(relLoc x+contents width) > clipRectangle right])
//		ifTrue: [velocity \(<- velocity*(-1@1)].
//	(velocity y < 0 and: [relLoc y < clipRectangle top])
//		ifTrue: [velocity \(<- velocity*(1@-1)].
//	(velocity y > 0 and: [(relLoc y+contents height) > clipRectangle bottom])
//		ifTrue: [velocity \(<- velocity*(1@-1)].
- displayOn:destForm at:(PT)aDisplayPoint clipBy:clipRectangle rule:(int)ruleInteger mask:aForm {
	PT relLoc;
	[super displayOn:destForm at:aDisplayPoint clipBy:clipRectangle rule:ruleInteger mask:aForm];
	relLoc = ptPlus(location, [clipRectangle origin]);
	if (X(velocity) < 0 && X(relLoc) < [clipRectangle left])
			velocity = ptTimes(velocity, pt(-1,1));
	if (X(velocity) > 0 && X(relLoc) + [contents width] > [clipRectangle right])
			velocity = ptTimes(velocity, pt(-1,1));
	if (Y(velocity) < 0 && Y(relLoc) < [clipRectangle top])
			velocity = ptTimes(velocity, pt(1,-1));
	if (Y(velocity) > 0 && Y(relLoc) + [contents height] > [clipRectangle bottom])
			velocity = ptTimes(velocity, pt(1,-1));
	return self;
}
.)C
.pp
The original Smalltalk statements are shown in the comments preceeding each
block of translated code. The translation of the first few lines in the method
were influenced primarily by rules from a file of application-specific 
information, of which three are shown here:
.(C
{ # location (PT) location }
{ # velocity (PT) velocity }
{ (id)displayOn:(id) at:(PT) clippingBox:(id) rule:(int) mask:(id) #
	(id) [displayOn:%1 at:(PT)%2 clipBy:%3 rule:(int)%4 mask:%5] }
.)C
The two instance variables, location and velocity, were inherited from
another application-specific class, PositionNode. The first two rules
declare that they are both of type PT (Point) and should be translated 
without change in spelling. The third rule specifies that methods and 
messages whose selector is displayOn:at:clippingBox:rule:mask: and whose
receiver and arguments type id, id, PT, id, int and id respectively,
should be translated into a message with the modified selector
displayOn:at:clipBy:rule:mask: and with argument types and positions 
as denoted in the right hand part of the rule. No declaration was provided
for the local variable relLoc, so its type was inferred from the type of 
the first statement that assigns it a value, namely
.(C
relLoc \(<- location + clipRectangle origin.
.)C
The translation of this statement was determined by two rules from a
different file of generic rules about low-level Smalltalk-80 objects.
.(C
{ # (PT) [origin] }
{ (PT)+ (PT) # (PT)'ptPlus(%0, %1)' }
.)C
The first rule denotes that the origin message, applied to an receiver
of any type, returns a Point, and the second that the + message sent to
an receiver of type Point with an argument of the same type translates 
as a call on the C function ptPlus which returns a value of type PT.
.pp
Currently, producer does nothing special for blocks, aside from giving them
a unique type (BLOCK) that can be tested by ordinary message rules. For
example, the `if' statements were produced by such a rule:
.(C
{ ifTrue:(BLOCK) # (STMT)'if (%0) %1' }
.)C

.H "Conclusions"
The primary conclusion that can be drawn from the results to date is that
small Smalltalk applications that do not lean heavily on complex features
of the Smalltalk environment can be translated to Objective-C with remarkably
little trouble. Only two man-weeks sufficed to build a reasonably effective
translation tool and a generic collection of rules that could translate a
263 line Smalltalk program into Objective-C with only 61 lines of application
specific information.  Once the application is operational, it may be
possible to draw additional conclusions about the overall merit of the
translation concept, for example by comparing the animation example's 
performance before and after translation.
.pp
This work has also identified several limitations in how the translation
program is currently implemented, but it is too early to know whether they
are serious enough to warrant fixing. For example, the scheme used for
handling Smalltalk-80 block expressions works primarily because of
serendipity, not because Smalltalk blocks are equivalent to any construct
that C provides. Experience may prove that Smalltalk-80 programmers
usually use blocks just as C programmers use simple conditional statements,
in which case there would be little need for anything more elaborate,
particularly since misses are automatically flagged as syntax errors when 
the generated code is compiled and could be repaired by hand. A number of
more elaborate schemes are also available, up to and including a direct
implementation of Smalltalk's scheme, and it is too soon to say which of
these will prove sufficient.
.pp
Several limitations have been identified in how rules are currently processed.
The fundamental restriction is that rules can only define data which is
interpreted by hard-coded logic, so it is not possible to write rules that
recognize and translate entities larger than an individual message expression.
For example, the current scheme could not eliminate wasteful Smalltalk idioms
like `Form under' by replacing the message with a constant, because this
would involve examining not only the type of the message's receiver, but
also its name. For much the same reason, it could not eliminate the 
unnecessary function call in the body of the first `if' statement by
translating it to:
.(C
X(velocity) *= -1;\**
.)C
.(f
\** X() and Y() are C macros, not functions. They are L-values and can be
used as the target of assignment statements.
.)f
If this restriction proves too limiting in practice, it could be relieved
by incorporating a general-purpose rule interpreter such as Prolog.
.pp
There are a number of smaller problems that should certainly be repaired.
Currently, rules have global scope and they should instead be attached to 
specific classes, methods, or blocks to provide finer control over how 
identifier spellings and types are assigned. Identifier rules should be 
organized into a type hierarchy, and types should be compared by something 
more sophisticated than mere equality of their names. These enhancements 
would increase the modularity and generality of the translation rules, but 
would not influence the range of translations that producer can perform.
.pp
The final result is that we have received the encouragement that we need
to pursue this idea further. Translation does appear to be a viable way
of integrating the best of two worlds into a comprehensive hybrid 
programming environment that spans a much larger segment of the 
software development life-spiral than ever before.
\Rogue\Monster\
else
  echo "will not over write ./producer.me"
fi
echo "Finished archive 2 of 5"
exit
----
Dieter H. Zebbedies ('dee-ter  ayech  'zeb-ed-eez)
 Zebb-Hoff Mach. Tool's Automated Manufacturing Project Cleveland, OH
 (USnail): 9535 Clinton Rd, Cleveland, OH 44144 (+216 631 6100) (+216 741-5994)
 (UUCP): ...{decvax,sun,cbosgd}!cwruecmp!zhmti!dieter
 (CSNET/ARPA/BITNET): dieter@CWRU.EDU

dietz@zhmti.UUCP (Dieter H. Zebbedies) (08/20/87)

"Producer", A package to translate Smalltalk-80 code to your favorite
object oriented language, Objective-C.

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -d ./src`
then
  mkdir ./src
  echo "mkdir ./src"
fi
if `test ! -s ./src/Type.m`
then
echo "writting ./src/Type.m"
cat > ./src/Type.m << '\Rogue\Monster\'
#include "Producer.h"
	TYPE types = { 0 };
	LOCAL id knownTypes;
	USE Set;
= Type : Constant CATEGORIES()
+ initialize { static BOOL beenHere;
	if (!beenHere) { beenHere = YES;
		self = Type; knownTypes = [Set new];

		// C base types
		types.ID = [self str:"id"];
		types.CHAR = [self str:"char"];
		types.SHORT = [self str:"short"];
		types.INT = [self str:"int"];
		types.LONG = [self str:"long"];
		types.FLOAT = [self str:"float"];
		types.DOUBLE = [self str:"double"];

		// Common derived types
		types.CSTRING = [self str:"STR"];
		types.POINT = [self str:"PT"];
		types.RECTANGLE = [self str:"RT"];

		// Language types
		types.BLOCK = [self str:"BLOCK"];
		types.STMT = [self str:"STMT"];
		types.SELECTOR = [self str:"SEL"];
		types.SHARED = [self str:"SHR"];

		// Misc
		types.UNKNOWN = [self str:"unknown"];
		types.ANY = [self str:"any"];
	}
	return self;
}
- type
	{ return self; }
=:
\Rogue\Monster\
else
  echo "will not over write ./src/Type.m"
fi
if `test ! -s ./src/gen.m`
then
echo "writting ./src/gen.m"
cat > ./src/gen.m << '\Rogue\Monster\'
#include "Producer.h"
#include "stdio.h"
#include "ctype.h"
= CATEGORIES()
	LOCAL unsigned indent = 0;
	LOCAL BOOL bol = YES;
	LOCAL IOD genFD = stdout;
	LOCAL STR yyfilename = "<stdin>";

// Debug option
EXPORT void po(o) id o; 
	{ [o show]; }
EXPORT void dbgo(o) id o; 
	{ IMPORT BOOL dbgFlag; if (dbgFlag) [o show]; }
EXPORT int yywrap() 
	{ IMPORT unsigned yylineno; yylineno = 1; return 1; }

// stockpile the last n tokens for printing in error messages
#define SIZ 30
	LOCAL char minPt[SIZ+10] = "";	// slop
	LOCAL STR inPt = &minPt[SIZ-1], maxPt = &minPt[SIZ-1];
EXPORT void stockToken(s) STR s; {
	if (!s) return;
	if (isalnum(*inPt) && isalnum(*s)) {
		if (inPt >= maxPt) inPt = minPt;
		*inPt++ = ' ';
	}
	while(*s) {
		if (inPt >= maxPt) inPt = minPt;
		*inPt++ = *s++;
	}
}
LOCAL printToken(iod) IOD iod; { STR outPt, stopPt;
	if (inPt >= maxPt)	{ outPt = minPt; stopPt = maxPt-1; }
	else 				{ outPt = inPt; stopPt = inPt-1; }
	for(;;) {
		if (outPt >= maxPt) outPt = minPt;
		putc(*outPt ? *outPt : ' ', iod);
		if (outPt++ == stopPt) break;
	}
}
EXPORT IOD yyopen(file, mode, iod) STR file, mode; IOD iod; {
	IMPORT IOD yyin; IMPORT unsigned yylineno;
	yylineno = 1; return freopen(yyfilename = file, mode, yyin=stdin);
}
	EXPORT int errorCount = 0;
EXPORT void wer(fmt, arg) STR fmt, arg; { IMPORT unsigned yylineno; 
	fflush(stdout); fflush(genFD); fflush(stderr);
	fprintf(stderr, "error: ");
	_doprnt(fmt, &arg, stderr); fprintf(stderr, "\n");
	fflush(stdout); fflush(genFD); fflush(stderr);
	errorCount++;
}
EXPORT void yyerror(fmt, arg) STR fmt, arg; { IMPORT unsigned yylineno; 
	fflush(stdout); fflush(genFD); fflush(stderr);
	fprintf(stderr, "error %3d:%s: ", yylineno, yyfilename);
	printToken(stderr); fprintf(stderr, " : ");
	_doprnt(fmt, &arg, stderr); fprintf(stderr, "\n");
	fflush(stdout); fflush(genFD); fflush(stderr);
	errorCount++;
}
	EXPORT BOOL infoFlag = NO;
EXPORT void info(fmt, arg) STR fmt, arg; { IMPORT unsigned yylineno; 
	if (!infoFlag) return;
	fflush(stdout); fflush(genFD); fflush(stderr);
	fprintf(stderr, "fyi   %3d:%s: ", yylineno, yyfilename);
	_doprnt(fmt, &arg, stderr); fflush(stderr);
}
// String copy
EXPORT STR strCopy(s) STR s; { return (STR)strcpy(malloc(strlen(s)+1), s); }

// fopen(genFD)
EXPORT void genOpen(className) STR className; {
	if (genFD != stdout) fclose(genFD);
	genFD = fopen(className, "w");
	indent = 0; bol = YES;
	if (!genFD) { fprintf(stderr, "cannot open %s for writing ", className);
		perror("");
		exit(-1);
	}
}
EXPORT void genReset() { indent = 0; bol = YES; }

// Generate: formatted, string, newline, char
EXPORT void gc(c) { BOOL eol = NO, discardSemi = NO;
	switch(c) { 
	case '\n': case '\r': case '\f': newline(); return;
	case '{': eol = YES; discardSemi = NO; break;
	case '}': indent--; eol = YES; discardSemi = YES; newline(); break;
	case '(': indent++; discardSemi = NO; break;
	case ')': indent--; discardSemi = NO; break;
	case ';': if (discardSemi) return; eol = YES; discardSemi = YES; break;
	default: discardSemi = NO; break;
	}
	if (bol) idn();
	putc(c, genFD); 
	if (eol) newline();
	if (c == '{'/*}*/) indent++;
}
EXPORT void gf(s, arg) STR s, arg; { _doprnt(s, &arg, genFD); }
EXPORT void gs(s) STR s; { while(*s) gc(*s++); }
EXPORT void gn() { bol = NO; newline(); }
LOCAL idn() { unsigned i;
	for (i = indent; i-- != 0; ) putc('\t', genFD);
	bol = NO;
}
LOCAL newline() {
	if (!bol) putc('\n', genFD);
	bol = YES;
}
\Rogue\Monster\
else
  echo "will not over write ./src/gen.m"
fi
if `test ! -s ./src/main.m`
then
echo "writting ./src/main.m"
cat > ./src/main.m << '\Rogue\Monster\'
#include "stdio.h"
#include "Producer.h"
= CATEGORIES()
	LOCAL BOOL showMsgTranslationFlag, showIdTranslationFlag;
STR *parseArguments(argc, argv) STR *argv; { unsigned i; USE Object;
	IMPORT BOOL dbgFlag, msgFlag, allocFlag, printFlag, lexFlag, infoFlag,
		autoFileFlag, stripCommentsFlag, infoFlag;
	IMPORT IOD dbgIOD;
	// settrap();	// trap interrupts
	[Object self];	// trigger initializes now
	dbgIOD = stderr;
	for (i = 1; i < argc; i++) { STR arg = argv[i];
		static char usage[]="usage: %s [-(dmaplgsci)] files ..";
		if (*arg == '-') 
			switch (*++arg) {
			case 'd': dbgFlag = YES; break;
			case 'm': msgFlag = YES; break;
			case 'a': allocFlag = YES; break;
			case 'p': printFlag = YES; break;
			case 'l': lexFlag = YES; break;
			case 'g': autoFileFlag = YES; break;
			case 's': stripCommentsFlag = YES; break;
			case 'c': stripCommentsFlag = NO; break;
			case 'i': infoFlag = YES; break;
			case 'M': showMsgTranslationFlag = YES; break;
			case 'I': showIdTranslationFlag = YES; break;
			default: fprintf(stderr, usage, argv[0]); bye(-2);
			}
		else return &argv[i];
	}
	return 0;
}
main(argc, argv) STR *argv; { USE Comment;
	IMPORT unsigned errorCount;
	STR *file = parseArguments(argc, argv);
	if (file) for (; *file; file++) {
			if (yyopen(*file, "r", stdin)) yyparse();
			else wer("cannot open %s\n", *file);
		}
	else yyparse(); 
	bye(errorCount != 0);
}
// Exit here.
bye(n) { static BOOL beenHere = 0; 
	IMPORT id msgTranslator, identifierTranslator;
	if (beenHere++) exit(n);
	if (showMsgTranslationFlag) {
		printf("msgTranslator============================\n");
		[msgTranslator show];
	}
	if (showIdTranslationFlag) {
		printf("identifierTranslator============================\n");
		[identifierTranslator show];
	}
	exit(n); 
}
@class(String, Block, ByteArray, Return, Selector, Comment, Stmt, AsciiFiler,
	Expr, Msg, StArray, Method, List, IdArray, Sequence, Cltn,
	Set, IntArray, Class, Identifier, MsgArgPattern, MsgNamePattern, 
	MsgTranslator, AbstractTranslation, FunctionTranslation, 
	MsgTranslation, StringTranslation, IdentifierTranslation,
	CharConstant, Constant, NumberConstant, SelectorConstant, StringConstant,
	Template, Type, ArgumentList, Scope)
@phyla CATEGORIES()
\Rogue\Monster\
else
  echo "will not over write ./src/main.m"
fi
if `test ! -s ./src/Producer.h`
then
echo "writting ./src/Producer.h"
cat > ./src/Producer.h << '\Rogue\Monster\'
#ifndef PRODUCER_H
#	include "Substrate.h"
#	undef CATEGORIES
#ifndef COXLIB
#	define CATEGORIES() (Producer, Collection, Primitive)
#else
#	define CATEGORIES() (Producer, Substrate, Primitive)
#endif
#	define ARYSIZ(x) (sizeof(x)/sizeof(*x))
#	define strEq(a, b) (strcmp(a, b) == 0)
	typedef struct _TYPES {
		id DEFAULT, ID, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE;
		id CSTRING, POINT, RECTANGLE;
		id BLOCK, STMT;
		id SELECTOR, SHARED;
		id UNKNOWN, ANY;
	} TYPE;
	IMPORT TYPE types;

#	define AbstractTranslation prAbstractTranslation
#	define ArgumentList prArgumentList
#	define Block prBlock
#	define CharConstant prCharConstant
#	define Class prClass
#	define Comment prComment
#	define Constant prConstant
#	define Expr prExpr
#	define FunctionTranslation prFunctionTranslation
#	define Identifier prIdentifier
#	define IdentifierTranslation prIdentifierTranslation
#	define List prList
#	define Method prMethod
#	define Msg prMsg
#	define MsgArgPattern prMsgArgPattern
#	define MsgNamePattern prMsgNamePattern
#	define MsgTranslation prMsgTranslation
#	define MsgTranslator prMsgTranslator
#	define Node prNode
#	define NumberConstant prNumberConstant
#	define Return prReturn
#	define Scope prScope
#	define Selector prSelector
#	define SelectorConstant prSelectorConstant
#	define StArray prStArray
#	define Stmt prStmt
#	define StringConstant prStringConstant
#	define StringTranslation prStringTranslation
#	define Template prTemplate
#	define Type prType

#define PRODUCER_H
#endif
\Rogue\Monster\
else
  echo "will not over write ./src/Producer.h"
fi
if `test ! -s ./src/st80.h`
then
echo "writting ./src/st80.h"
cat > ./src/st80.h << '\Rogue\Monster\'
#ifndef PRODUCERTEST_H
#	include "Layers.h"
#	define ARYSIZ(x) (sizeof(x)/sizeof(*x))
#	define strEq(a, b) (strcmp(a, b) == 0)

#	undef CATEGORIES()
#	define CATEGORIES() (ProducerTest, Collecting, Primitive)
#	define unknown id
#	define PRODUCERTEST_H
#endif
\Rogue\Monster\
else
  echo "will not over write ./src/st80.h"
fi
if `test ! -s ./src/y.tab.h`
then
echo "writting ./src/y.tab.h"
cat > ./src/y.tab.h << '\Rogue\Monster\'

typedef union 	TYP { id O; char B; char *S; } YYSTYPE;
extern YYSTYPE yylval;
# define IDENTIFIER 257
# define DIGITS 258
# define KEYWORD 259
# define STRING 260
# define CHARCON 261
# define DOUBLESPECIAL 262
# define  _ 95
# define VariableIdentifier 263
\Rogue\Monster\
else
  echo "will not over write ./src/y.tab.h"
fi
if `test ! -s ./src/gram.y`
then
echo "writting ./src/gram.y"
cat > ./src/gram.y << '\Rogue\Monster\'
%{
/* Grammar for Smalltalk-80
 *		3 shift/reduce, 0 reduce/reduce conflicts
 */
#include <stdio.h>
#include "objc.h"
#include "Producer.h"
= CATEGORIES()
	USE Block, Expr, List, Array, Type, StArray, Msg, Method, Return,
		Selector, Stmt, Identifier, IdentifierTranslation, StringTranslation,
		FunctionTranslation, NumberConstant, SelectorConstant, CharConstant, 
		StringConstant, MsgTranslation, Template, ArgumentList, Class, Comment;
	EXPORT BOOL printFlag,
		isFactory = NO;
	IMPORT id findSymbol();
	LOCAL id thisClass = nil;
	IMPORT id msgTranslator;
%}
%union	TYP { id O; char B; char *S; }
%type	<O> LocalVariables VarList PrimMarker Type Method MethodName Keyword
%type	<O> KwdMethodDecl StmtList Expr AssignmentList Primary 
%type	<O> UnaryObjDesc BinaryObjDesc SimpleMsgExpr UnaryExpr BinaryExpr
%type	<O> KeywordExpr KeywordArgList CascadedMsgExpr CascadedMsg
%type	<O> Literal ArrayMemberList ArrayMember Block BinarySelector
%type	<O> VariableName UnarySelector Template BlockVarList KeywordList
%type	<O> InferenceRule ObjcFunctionArgList ObjcFunctionPattern BlockVariables
%type	<O> ObjcKeywordPattern ObjcMsgPattern OptionalType
%type	<O> ParameterDesignator KeywordPattern PatternType TemplateType
%type	<O> CharacterConstant NumberConstant StringConstant Keyword
%type	<B> SpecialCharacter
%token	<S> IDENTIFIER DIGITS KEYWORD STRING CHARCON DOUBLESPECIAL
%token	<B> '%' '|' '&' '?' '#' '!' ',' '_'
%token	<B> '+' '-' '/' '\\' '*' '~' '<' '>' '=' '@' 

%left '_' 
%left IDENTIFIER STRING UnarySelector VariableIdentifier
%right KEYWORD BinarySelector
%start ChunkList
%%
ChunkList:
	| ChunkList Chunk { USE Comment; [Comment gen]; }
	;
Chunk: VariableName KEYWORD '#' VariableName
		KEYWORD StringConstant KEYWORD StringConstant 
		KEYWORD StringConstant KEYWORD StringConstant '!' {
			[Comment gen];
			if (thisClass) { [thisClass gen]; [thisClass free]; }
			thisClass = [Class name:findSymbol($4)];
			[thisClass superclass:findSymbol($1)];
			[thisClass instanceVariableNames:$6];
			[thisClass classVariableNames:$8];
			[thisClass poolDictionaries:$10];
			[thisClass category:$12];
			[thisClass gen];
		}
	| VariableName KEYWORD STRING '!' 
		{isFactory=NO;} Methods Sep
	| VariableName VariableName KEYWORD STRING '!' 
		{isFactory=YES;} Methods Sep
	| '{' InferenceRule '}' 
		{ [Comment free]; }
	| '{' error '}' 
	| error '!'
	;
Sep: '!'
	| Sep '!'
	;
Methods: 
	| Methods Method '!' 
		{ [Comment gen]; [$2 gen]; [$2 free]; }
	| Methods error '!' 
		{ [Comment gen]; }
	;
/* Declare a new method */
Method: MethodName LocalVariables 
			{ [$$=$1 variables:$2]; }
		PrimMarker StmtList 
			{ [$$ primitive:$4]; [$$ statements:$5]; }
	;
MethodName: UnarySelector
		{ $$ = [Method selector:$1 asFactory:isFactory]; }
	| BinarySelector VariableName
		{ $$ = [Method selector:[$1 argument:$2] asFactory:isFactory]; }
	| KwdMethodDecl 
		{ $$ = [Method selector:$1 asFactory:isFactory]; }
	;
PrimMarker: { $$ = nil; }
	| '<' KEYWORD NumberConstant '>'
		{ $$ = [NumberConstant sprintf:"primitive(%s);", [$3 str]]; [$3 free]; }
	;
LocalVariables: { $$ = nil; }
	| '|' VarList '|' 
		{ $$ = $2; }
	;
VarList: { $$ = nil; }
	| VarList VariableName 
		{ $$ = $1 ? $1 : [List new]; [$$ add:$2]; }
	;
KwdMethodDecl: Keyword VariableName 
	{ [$$=$1 argument:$2]; }
	| KwdMethodDecl Keyword VariableName 
		{ [$$=$1 add:[$2 argument:$3]]; }
	;
/* Statements and expressions */
StmtList: '^' Expr 
	{ $$ = [Return expr:$2]; }
	| Expr 
		{ $$ = [Stmt expr:$1]; }
	| Expr '.' 
		{ $$ = [Stmt expr:$1]; }
	| Expr '.' StmtList 
		{ [$$=[Stmt expr:$1] successor:$3]; }
	| error '.' 
		{ wer("erroneous statement ignored"); $$=nil; }
	;
Expr: AssignmentList Primary 
	{ $$ = [Expr assign:$1 value:$2]; }
	| AssignmentList SimpleMsgExpr 
		{ $$ = [Expr assign:$1 value:$2]; }
	| AssignmentList SimpleMsgExpr CascadedMsgExpr
		{ [$$ = [Expr assign:$1 value:$2] cascade:$3]; }
	;
AssignmentList: { $$ = nil; }
	| AssignmentList VariableName '_'
		{ $$ = $1 ? $1 : [List new]; [$$ add:findSymbol($2)]; }
	;
CascadedMsgExpr: CascadedMsg 
	{ $$=[Expr assign:nil value:$1]; }
	| CascadedMsgExpr CascadedMsg 
		{ [$$=$1 add:[Expr assign:nil value:$2]]; }
	;
CascadedMsg: ';' UnarySelector 
	{ $$ = [Msg selector:$2]; }
	| ';' BinarySelector UnaryObjDesc 
		{ $$ = [Msg selector:[$2 argument:$3]]; }
	| ';' KeywordArgList 
		{ $$ = [Msg selector:$2]; }
	;
Primary: VariableName 
	{ $$ = findSymbol($1); }
	| Literal | Block | '(' Expr ')' 
		{ $$ = $2; }
	;
SimpleMsgExpr: UnaryExpr | BinaryExpr | KeywordExpr ;
UnaryObjDesc: Primary | UnaryExpr ;
UnaryExpr: UnaryObjDesc UnarySelector 
	{ $$ = [Msg receiver:$1 selector:$2]; } ;
BinaryObjDesc: UnaryObjDesc | BinaryExpr ;
BinaryExpr: BinaryObjDesc BinarySelector UnaryObjDesc
		{ $$ = [Msg receiver:$1 selector:[$2 argument:$3]]; } ;
KeywordExpr: BinaryObjDesc KeywordArgList
		{ $$ = [Msg receiver:$1 selector:$2]; }
	;
KeywordArgList: Keyword BinaryObjDesc	
	{ [$$=$1 argument:$2]; }
	| KeywordArgList Keyword BinaryObjDesc 
		{ [$$=$1 add:[$2 argument:$3]]; }
	;
Literal: CharacterConstant | StringConstant | NumberConstant
	| '#' '(' ArrayMemberList ')' 
		{ $$ = $3; }
	| '#' UnarySelector 
		{ $$=[SelectorConstant name:$2]; [$2 free]; }
	| '#' BinarySelector 
		{ $$=[SelectorConstant name:$2]; [$2 free]; }
	| '#' KeywordList 
		{ $$=[SelectorConstant name:$2]; [$2 free]; }
	;
ArrayMemberList: { $$ = nil; }
	| ArrayMemberList ArrayMember 
		{ [$$ = $1 ? $1 : [StArray new] add:$2]; }
	;
ArrayMember: CharacterConstant | StringConstant | NumberConstant 
	| UnarySelector | BinarySelector | KeywordList 
	| '(' ArrayMemberList ')' 
		{ $$ = $2; }
	;
Block: '[' BlockVariables StmtList ']' 
	{ $$ = [$2 statements:$3]; }
	| '[' BlockVariables ']' 
		{ $$ = $2; }
	;
BlockVariables: 
	{ $$ = [Block new]; }
	| BlockVarList '|' 
		{ $$ = [[Block new] variables:$1]; }
	;
BlockVarList: ':' VariableName 
	{ [$$ = [List new] add:$2]; }
	| BlockVarList ':' VariableName 
		{ [$$=$1 add:$3]; }
	;
/* Type inferencing rules */
InferenceRule: '#' PatternType '[' ObjcMsgPattern ']'
		{ [msgTranslator install:[Template receiverType:[$4 receiverType]
			selector:[$4 selector]] translation:[$4 type:$2]]; }
	| Template '#' PatternType '[' ObjcMsgPattern ']'
		{ [msgTranslator install:$1 translation:[$5 type:$3]]; }
	| Template '#' PatternType ObjcFunctionPattern
		{ [msgTranslator install:$1 translation:[$4 type:$3]]; }
	| Template '#' PatternType StringConstant 
		{ [msgTranslator install:$1
			translation:[StringTranslation type:$3 translation:$4]]; }
	| '#' VariableName PatternType VariableName
		{ [IdentifierTranslation sourceName:$2 targetType:$3 targetName:$4]; }
	;
Template: TemplateType UnarySelector
		{ $$ = [Template receiverType:$1 selector:$2]; }
	| TemplateType BinarySelector TemplateType
		{ $$ = [Template receiverType:$1 selector:[$2 type:$3]]; }
	| TemplateType KeywordPattern
		{ $$ = [Template receiverType:$1 selector:$2]; }
	;
KeywordPattern: Keyword PatternType 
	{ [$$=$1 type:$2]; }
	| KeywordPattern Keyword PatternType
		{ [$$=$1 add:$2]; [$2 type:$3]; }
	;
ObjcFunctionPattern: VariableName '(' ObjcFunctionArgList ')'
		{ $$ = [FunctionTranslation name:$1 args:$3]; }
	| VariableName '(' ')'
		{ $$ = [FunctionTranslation name:$1 args:0]; }
	;
ObjcFunctionArgList: PatternType ParameterDesignator
		{ $$ = [ArgumentList type:$1 name:$2]; }
	| ObjcFunctionArgList ',' PatternType ParameterDesignator
		{ [$$=$1 add:[ArgumentList type:$3 name:$4]]; }
	;
ObjcMsgPattern: PatternType UnarySelector
		{ $$ = [MsgTranslation receiverType:$1 selector:$2]; }
	| PatternType ObjcKeywordPattern
		{ $$ = [MsgTranslation receiverType:$1 selector:$2]; }
	;
ObjcKeywordPattern: Keyword PatternType ParameterDesignator
		{ [$1 type:$2]; [$$=$1 argument:$3]; }
	| ObjcKeywordPattern Keyword PatternType ParameterDesignator
		{ [$$=$1 add:$2]; [$2 type:$3]; [$2 argument:$3]; }
	;
ParameterDesignator: VariableName
	| '%' DIGITS { $$=[NumberConstant sprintf:"%%%s", $2]; }
	;
/* Token Packaging */
KeywordList: KEYWORD { $$ = [Selector str:$1]; }
	| KeywordList KEYWORD { $$ = [$1 concatenateSTRAndFreeReceiver:$2]; }
	;
BinarySelector: '-' { $$ = [Selector str:"-"]; }
	| SpecialCharacter 
		{ char b[2]; b[0]=$1; b[1]=0; $$ = [Selector str:b]; }
	| DOUBLESPECIAL { $$ = [Selector str:$1]; }
	;
SpecialCharacter: '+' | '/' | '\\' | '*' | '~' | '<'
	| '>' | '=' | '@' | '%' | '&' | '?' | ',' | '|'
	;
PatternType: OptionalType { $$ = $1 ? $1 : types.ID; };
TemplateType: OptionalType { $$ = $1 ? $1 : types.ANY; };
OptionalType: { $$ = 0; } | '(' Type ')' { $$ = $2; };
Type: IDENTIFIER { $$=[Type str:$1]; };
VariableName: IDENTIFIER { $$=[Identifier str:$1]; };
UnarySelector: IDENTIFIER { $$ = [Selector str:$1]; };
CharacterConstant: CHARCON { $$ = [CharConstant str:$1]; };
NumberConstant: DIGITS { $$ = [NumberConstant str:$1]; }
	| '-' DIGITS %prec KEYWORD { $$ = [NumberConstant sprintf:"-%s", $2]; }
	;
StringConstant: STRING { $$ = [StringConstant str:$1]; };
Keyword: KEYWORD { $$ = [Selector str:$1]; };
%%

\Rogue\Monster\
else
  echo "will not over write ./src/gram.y"
fi
if `test ! -s ./src/lex.l`
then
echo "writting ./src/lex.l"
cat > ./src/lex.l << '\Rogue\Monster\'
%{
#include "Producer.h"
#include "y.tab.h"
	USE Comment;
	LOCAL STR collect();
	EXPORT BOOL lexFlag = NO;
	IMPORT BOOL stripCommentsFlag;
#ifndef OBJC_COX
= CATEGORIES()
#endif
/* Intrudes between lexer and parser for token-level debugging */
EXPORT int yylex() { STR typeStr, tokenValue; LOCAL char b[2]={0};
	int type = rawlexer();
	switch(type) {
	case DIGITS: typeStr="DIGITS"; tokenValue = yylval.S; break;
	case KEYWORD: typeStr="KEYWORD"; tokenValue = yylval.S; break;
	case IDENTIFIER: typeStr="IDENTIFIER"; tokenValue = yylval.S; break;
	case STRING: typeStr="STRING"; tokenValue = yylval.S; break;
	case CHARCON: typeStr="CHARCON"; tokenValue = yylval.S; break;
	default: b[0] = yylval.B; typeStr = tokenValue = b; break;
	}
	stockToken(tokenValue);
	if (lexFlag) printf("::%3d=%10s: %s\n", type, typeStr, tokenValue);
	return type;
}
LOCAL STR bitsToHex(s) STR s; { LOCAL char buf[80];
	LOCAL char charToHex[]="0123456789abcdef";
	unsigned short out = 0; STR p; int shiftBy;
	p = buf; *p++ = '0'; *p++ = 'x';
	for (shiftBy = 3; *s; shiftBy--,s++) {
		out |= (unsigned)(*s != '0') << shiftBy;
		if (shiftBy == 0) {
			*p++ = charToHex[out];
			out = 0;
			shiftBy = 3;
		}
	}
	*p = 0; return buf;
}
GETC(iod) IOD iod; { LOCAL char buf[BUFSIZ] = {0}; LOCAL STR p = buf;
	if (*p == 0) { p = buf; *p = 0;
		if (fgets(buf, sizeof(buf), iod) == NULL) { 
			STR q = &buf[strlen(buf)];
			*q++ = EOF; *q = 0;
		}
		if (!stripCommentsFlag) [Comment str:buf];
	}
	return *p++;
}
#      undef input
#      define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):GETC(yyin))==10?\
	(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
#      define yylex rawlexer
%}
%%
[ \t\n\f\r]+ { ; }
"\"" { yylval.S = collect(yyleng); }
"'" { yylval.S = collect(yyleng); return STRING; }
[A-Za-z][A-Za-z0-9]* { yylval.S = yytext; return IDENTIFIER; }
[A-Za-z][A-Za-z0-9]*: { yylval.S = yytext; return KEYWORD; }
[+/\\*~<>=@%|&?][+/\\*~<>=@%|&?] { yylval.S = yytext; return DOUBLESPECIAL; }
[0-9]+ |
[0-9]*\.[0-9]+ { yylval.S = yytext; return DIGITS; }
2r[0-1]+ { yylval.S = bitsToHex(&yytext[2]); return DIGITS; }
\$.  { yylval.S = &yytext[1]; return CHARCON; }
\$!! { yylval.S = "!"; return CHARCON; }
.  { return yylval.B = *yytext; }
%%
/* Collect a "String" 'CharacterConstant', #command or comment
 *	The item to be collected is identified (in `what') from the
 *	first character in yytext.
 *
 *	To save copying time, we collect as much as will fit directly in yytext[].
 *	An instance of String is then created to hold any overflows. The str
 *	returned from here will locate the result, whether held
 *	in yytext or aString.
 */
LOCAL STR collect(len)
	register short len;
{
	USE ByteArray; register short c;
	LOCAL id overflow = 0; char what = *yytext;
	if (overflow) overflow = [overflow free]; /* from last time around */
	for(;;) {
		if (len >= YYLMAX - 1) {
			yytext[len] = 0; len = 0;
			if (overflow) overflow = [overflow concatenateSTR:yytext];
			else overflow = [ByteArray str:yytext];
		}
		switch(yytext[len++] = c = input()) {
		case '\'': if (what == '\'') {
				if ((c = input()) == '\'') { yytext[len++] = c; continue; }
				else { unput(c); break; }
			} else continue;
		case '"': if (what == '"') break; else continue;
		case '*': if (what != '/') continue;
			if ((c = input()) == '/') { yytext[len++] = c; break; }
			unput(c); continue;
		case '\\': yytext[len++] = input(); continue;
		case '\n': continue;
		case 0: wer("Unterminated string or charconst"); break;
		default: continue;
		}
		yytext[len] = 0;
		return overflow
			? [(overflow = [overflow concatenateSTR:yytext]) str]
			: yytext;
	}
}
\Rogue\Monster\
else
  echo "will not over write ./src/lex.l"
fi
if `test ! -s ./src/Makefile`
then
echo "writting ./src/Makefile"
cat > ./src/Makefile << '\Rogue\Monster\'
# Producer: The Smalltalk to ObjectiveC Translator
OCOBJ= Node.o List.o Block.o Comment.o \
	ByteArray.o \
		Symbol.o \
		Constant.o \
			Type.o \
			CharConstant.o \
			NumberConstant.o \
			SelectorConstant.o \
			StringConstant.o \
	Expr.o StArray.o Class.o \
	Msg.o Method.o Stmt.o Return.o \
	MsgArgPattern.o \
	MsgNamePattern.o \
	MsgTranslator.o \
	Template.o \
	Selector.o \
		ArgumentList.o \
	Identifier.o \
	IdentifierTranslation.o \
	AbstractTranslation.o \
		FunctionTranslation.o \
		MsgTranslation.o \
		StringTranslation.o \
	Scope.o
YACCOBJ=gram.o
LEXOBJ=lex.o
CCOBJ=gen.o main.o
OBJ=$(OCOBJ) $(YACCOBJ) $(LEXOBJ) $(CCOBJ)
LIBS=/u/ui/sb/Substrate.a
OBJC=objcc -q -g
MISC=main.m gram.y lex.l gen.m Producer.h 
SRC=README Makefile $(MISC) `_suffix .m $(OCOBJ) $(CCOBJ) | tr ' ' '\012' | sort`

.SUFFIXES:
.SUFFIXES: .y .l .m .o .c .me .i .f
all: METHODDECLS.o producer
producer: $(OBJ); $(OBJC) $(OBJ) && mv a.out producer
clean:		; rm -f *.o *.c [cpCP]_* log core gram.m lex.m
.y.o:		; yacc -dv $< && mv y.tab.c $*.m && $(OBJC) -c $*.m
.l.o:		; lex $< && mv lex.yy.c $*.m && $(OBJC) -c $*.m
.m.o:		; $(OBJC) -c -nRetain $<
.m.c:		; $(OBJC) -c $<
.me.i:		; me -i -t /u/cox/src/mac.me $<
.me.f:		; me -t /u/cox/src/mac.me $< >$$$$.f && mv $$$$.f $*.f
v.m: v.st	; -producer RULES/* v.st >v.m
v.o: v.m	; objc v.m -c -Retain -g -q -I../wg -I../ui $C
test:		; rm -f v.m; make v.o
wc:			; wc $(SRC)
\Rogue\Monster\
else
  echo "will not over write ./src/Makefile"
fi
if `test ! -s ./src/design.me`
then
echo "writting ./src/design.me"
cat > ./src/design.me << '\Rogue\Monster\'
Smalltalk Syntax consists of
	identifiers
	literal constants
	message expressions
		Return type
		Argument types

Literal constant typing is explicit from context
	Integer
	Floating Point
	String
	Character

Identifier type inferencing
	Identifier name transformation: How to specify scope of change?
	The type of each identifier is the type of the first assignment.
	Instance variables: generate declaration at tail of file after
		assignments have provided a type for each?
	Inherited variables: do these appear in methods of Smalltalk 
		subclasses?

Message expression type inferencing
	(int) do:(TYPE) this:(TYPE) to:(TYPE) that:(TYPE)
	Return type and argument types are taken from category files
		after performing any message name transforms

Method type inferencing
	When Objective-C method exists by the same name, use types from
		that
	Otherwise the type is determined after inferencing variable types.

Static polymorphism
	When translation of messages should depend on the (static) type of
	the receiver; e.g.
		(10@20) extent:(30@40) -> [Rectangle origin:pt(10,20) extent:(30@40)]
		aRectangle extent:(30@40) -> [Rectangle extent:pt(30@40)]
	or
		aPoint x 				-> X(aPoint)
		aRectangle origin 		-> aRectangle->origin
		aRectangle left			-> L(aRectangle)
	or better yet
		2 + 3					-> 2+3
		2.3 + 4.8				-> 2.3 + 4.8
		aPoint + anotherPoint 	-> ptPlus(aPoint, anotherPoint)
		aPoint + 3				-> ptPlusInt(aPoint, 3)

Notation:
	ReceiverType MessageExpression -> ReturnType FormatString
	\________Source_____________/	  \______Target_________/
		Default:
			ReceiverType:			matches id
			ReturnType:				id
			FormatString:			message expression

	Examples:
	(int)+(int)						-> $1 + $2
	(float)+(float)					-> $1 + $2
	(PT)+(PT)						-> ptPlus($1, $2)
	(PT)+(int)						-> ptPlusInt($1, $2)
\Rogue\Monster\
else
  echo "will not over write ./src/design.me"
fi
if `test ! -s ./src/Symbol.m`
then
echo "writting ./src/Symbol.m"
cat > ./src/Symbol.m << '\Rogue\Monster\'
/*{ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Symbol
	My instances in only a single copy, allowing them to be tested for
	equality via == instead of isEqual:

bjc: A prototype; not tested under load. The hash and isEqual: methods
	have broken since I was here last (library incompatibilities?)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }*/
#include "Producer.h"
	USE Set;
= Symbol:ByteArray CATEGORIES() { }
	LOCAL id symbolTable;

+ initialize
	{ if (!symbolTable) symbolTable = [Set new]; }
+ symbolTable
	{ return symbolTable; }
+ str:(STR)aStr 
	{ return [symbolTable filter:[super str:aStr]]; }
+ name:aByteArray 
	{ return [self str:[aByteArray str]]; }
- free 
	{ return nil; }
- str:(STR)aStr 
	{ return [self cannotModifyError]; }
- (char)charAt:(unsigned)anOffset put:(char)aChar 
	{ return (char)[self cannotModifyError]; }
- sort 
	{ return [self cannotModifyError]; }
- concat:aStr 
	{ return [self cannotModifyError]; }
- concatSTR:(STR)aCString
	{ return [self cannotModifyError]; }
- concatenateAndFreeReceiver:aByteArray 
	{ return [self cannotModifyError]; }
- concatenateSTRAndFreeReceiver:(STR)aString 
	{ return [self cannotModifyError]; }
- concatenateSTR:(STR)aString 
	{ return [self cannotModifyError]; }
- concatenate:aByteArray
	{ return [self cannotModifyError]; }
- cannotModifyError
	{ return [self error:"the bytes in a %s are invarient", [self name]]; }
#ifdef NOTWORKING
- (unsigned)hash 
	{ return (unsigned)self; }
- (BOOL)isEqual:anObject
	{ return self == anObject; }
#endif
=:

\Rogue\Monster\
else
  echo "will not over write ./src/Symbol.m"
fi
if `test ! -s ./src/ByteArray.m`
then
echo "writting ./src/ByteArray.m"
cat > ./src/ByteArray.m << '\Rogue\Monster\'
/*{ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ByteArray.m
	Do not be misled by the superficial resemblance between this class
	and the BytArray class in functionality, method names, implementation, 
	and usage. They are totally different.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }*/
#include <stdio.h>	/* @retain */
#include "Producer.h"
#include "vectors.h"	/* @retain */
#define badIndex(offset) ((unsigned)(offset) >= (unsigned)capacity)
#define goodIndex(offset) (!badIndex(offset))
	LOCAL char typeStr[]="\"";
	IMPORT int strlen(), atoi();
	IMPORT long atol();
	IMPORT double atof();
	IMPORT STR strcpy(), strcat();
	IMPORT unsigned _strhash();

= ByteArray:Array CATEGORIES() { }

// Indexed variable typing
+ (unsigned)ndxVarSize { return sizeof(char); }
+ (STR)ndxVarType { return typeStr; }
- (STR)describe { return typeStr; }

// Instance creation: Note that capacity records the capacity actually
//	available for characters. This is one more than the number requested
//	to guarantee that a null terminator will exist.
+ new { return [self new:0]; }
+ new:(unsigned)nExtra { self = (*_alloc)(self, nExtra+1);
	capacity = nExtra + 1; return self; 
}
+ str:(STR)aStr { unsigned n; if (aStr == 0) aStr = "";
	n = strlen(aStr); self = (*_alloc)(self, n+1);
	strcpy(IV(self), aStr); capacity = n+1; return self;
}
#define VA_TYPE int
+ sprintf:(STR)fmt; VA_TYPE va_alist; { char buf[BUFSIZ];
#ifdef BOOTSTRAP	/* @retain */
typedef int FILE;
#endif
#include "varargs.h"	/* @retain */
#ifdef BOOTSTRAP	/* @retain */
typedef char *va_list;
#endif
#ifdef _IOSTRG		/* @retain */
	{
	va_list ap;
	FILE iod;
	iod._cnt = sizeof(buf); iod._base = iod._ptr = buf;
	iod._flag = _IOWRT+_IOSTRG; va_start(ap);
	_prn(fmt, ap, &iod); va_end(ap);
	*iod._ptr = '\0';
	}
#else
# define INT int
	{
	va_list ap;
	int ilist[10]; register int *ip = ilist, i;
	va_start (ap);
	for (i = 0; i < 10; i++)
		*ip++ = va_arg(ap, INT);
	va_end (ap);
	ip = ilist;
	sprintf (buf, fmt, ip[0], ip[1], ip[2], ip[3], ip[4], ip[5],
		 ip[6], ip[7], ip[8], ip[9]);
	}
#endif
	return [self str:buf];
}
// Convert to indicated type
- (int)asInt { return atoi(IV(self)); } 
- (long)asLong { return atol(IV(self)); }
- (double)asFloat { return atof(IV(self)); }

// Accessing
- (STR)str { return IV(self); }
- str:(STR)aStr { strncpy(IV(self), aStr, capacity-1);
	IV(self)[capacity-1] = '\0'; return self; }
- (char)charAt:(unsigned)anOffset { return goodIndex(anOffset) ? 
	IV(self)[anOffset] : (char)[self boundsViolation:anOffset];
}
- (char)charAt:(unsigned)anOffset put:(char)aChar { STR p = IV(self)+anOffset;
	if goodIndex(anOffset) { char tmp= *p; *p=aChar; return tmp; }
	else return (char)[self boundsViolation:anOffset];
}
	LOCAL int cmp(a, b) char *a, *b; { return *a-*b; }
- sort { qsort(IV(self), capacity-1, sizeof(char), cmp); return self; }

#ifdef OBSOLETE
// Concatenate aStr to self. Reply 0 if truncation occurred.
- concat:aStr { return [self concatSTR:[aStr str]]; }
- concatSTR:(STR)aCString { unsigned me, l; if (aCString == 0) return 0;
	me = strlen(IV(self)); l = capacity-1;
	if (l > me) strncpy(IV(self)+me, aCString, l-me); 
	IV(self)[capacity-1] = '\0';
	return (l > me + strlen(aCString)) ? self : nil;
}
#endif
- concatenateAndFreeReceiver:aByteArray 
	{ return [self concatenateSTRAndFreeReceiver:[aByteArray str]]; }
- concatenateSTRAndFreeReceiver:(STR)aString 
	{ id tmp = [self concatenate:aString]; [self free]; return tmp; }
- concatenateSTR:(STR)aString 
	{ return [isa sprintf:"%s%s", [self str], aString]; }
- concatenate:aByteArray
	{ return [self concatenateSTR:[aByteArray str]]; }

// Comparing and hashing: hash must correlate with isEqual:
LOCAL int arycmp(obj, str) id obj; register STR str; {
	register unsigned siz = obj->capacity; register STR p = IV(obj);
	for (; siz--; p++, str++) if (*p != *str) return *p - *str;
	return 0;
}
- (int)compare:aStr { return aStr ? arycmp(self, [aStr str]) : NO; }
- (int)compareSTR:(STR)aStr { return aStr ? arycmp(self, aStr) : NO; }
- (BOOL)isEqual:aStr { return aStr ? arycmp(self, [aStr str]) == 0 : NO; }
- (BOOL)isEqualSTR:(STR)aStr { return aStr ? arycmp(self, aStr) == 0 : NO; }
- (BOOL)isCopyOf:anObject {
	return [super isCopyOf:anObject]
		&& (arycmp(self, IV(anObject)) == 0);
}
- (unsigned)hash 
	{ return _strhash(IV(self)); }
=:
\Rogue\Monster\
else
  echo "will not over write ./src/ByteArray.m"
fi
if `test ! -s ./src/y.output`
then
echo "writting ./src/y.output"
cat > ./src/y.output << '\Rogue\Monster\'

state 0
	$accept : _ChunkList $end 
	ChunkList : _    (1)

	.  reduce 1

	ChunkList  goto 1

state 1
	$accept :  ChunkList_$end 
	ChunkList :  ChunkList_Chunk 

	$end  accept
	error  shift 5
	IDENTIFIER  shift 6
	{  shift 4
	.  error

	VariableName  goto 3
	Chunk  goto 2

state 2
	ChunkList :  ChunkList Chunk_    (2)

	.  reduce 2


state 3
	Chunk :  VariableName_KEYWORD # VariableName KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant ! 
	Chunk :  VariableName_KEYWORD STRING ! $$4 Methods Sep 
	Chunk :  VariableName_VariableName KEYWORD STRING ! $$6 Methods Sep 

	IDENTIFIER  shift 6
	KEYWORD  shift 7
	.  error

	VariableName  goto 8

state 4
	Chunk :  {_InferenceRule } 
	Chunk :  {_error } 
	OptionalType : _    (123)

	error  shift 10
	#  shift 11
	(  shift 15
	.  reduce 123

	Template  goto 12
	InferenceRule  goto 9
	OptionalType  goto 14
	TemplateType  goto 13

state 5
	Chunk :  error_! 

	!  shift 16
	.  error


state 6
	VariableName :  IDENTIFIER_    (126)

	.  reduce 126


state 7
	Chunk :  VariableName KEYWORD_# VariableName KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant ! 
	Chunk :  VariableName KEYWORD_STRING ! $$4 Methods Sep 

	STRING  shift 18
	#  shift 17
	.  error


state 8
	Chunk :  VariableName VariableName_KEYWORD STRING ! $$6 Methods Sep 

	KEYWORD  shift 19
	.  error


state 9
	Chunk :  { InferenceRule_} 

	}  shift 20
	.  error


state 10
	Chunk :  { error_} 

	}  shift 21
	.  error


state 11
	InferenceRule :  #_PatternType [ ObjcMsgPattern ] 
	InferenceRule :  #_VariableName PatternType VariableName 
	OptionalType : _    (123)

	IDENTIFIER  shift 6
	(  shift 15
	.  reduce 123

	VariableName  goto 23
	OptionalType  goto 24
	PatternType  goto 22

state 12
	InferenceRule :  Template_# PatternType [ ObjcMsgPattern ] 
	InferenceRule :  Template_# PatternType ObjcFunctionPattern 
	InferenceRule :  Template_# PatternType StringConstant 

	#  shift 25
	.  error


state 13
	Template :  TemplateType_UnarySelector 
	Template :  TemplateType_BinarySelector TemplateType 
	Template :  TemplateType_KeywordPattern 

	IDENTIFIER  shift 29
	KEYWORD  shift 48
	DOUBLESPECIAL  shift 32
	%  shift 43
	|  shift 47
	&  shift 44
	?  shift 45
	,  shift 46
	+  shift 34
	-  shift 30
	/  shift 35
	\\  shift 36
	*  shift 37
	~  shift 38
	<  shift 39
	>  shift 40
	=  shift 41
	@  shift 42
	.  error

	Keyword  goto 33
	BinarySelector  goto 27
	UnarySelector  goto 26
	KeywordPattern  goto 28
	SpecialCharacter  goto 31

state 14
	TemplateType :  OptionalType_    (122)

	.  reduce 122


state 15
	OptionalType :  (_Type ) 

	IDENTIFIER  shift 50
	.  error

	Type  goto 49

state 16
	Chunk :  error !_    (10)

	.  reduce 10


state 17
	Chunk :  VariableName KEYWORD #_VariableName KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant ! 

	IDENTIFIER  shift 6
	.  error

	VariableName  goto 51

state 18
	Chunk :  VariableName KEYWORD STRING_! $$4 Methods Sep 

	!  shift 52
	.  error


state 19
	Chunk :  VariableName VariableName KEYWORD_STRING ! $$6 Methods Sep 

	STRING  shift 53
	.  error


state 20
	Chunk :  { InferenceRule }_    (8)

	.  reduce 8


state 21
	Chunk :  { error }_    (9)

	.  reduce 9


state 22
	InferenceRule :  # PatternType_[ ObjcMsgPattern ] 

	[  shift 54
	.  error


state 23
	InferenceRule :  # VariableName_PatternType VariableName 
	OptionalType : _    (123)

	(  shift 15
	.  reduce 123

	OptionalType  goto 24
	PatternType  goto 55

state 24
	PatternType :  OptionalType_    (121)

	.  reduce 121


state 25
	InferenceRule :  Template #_PatternType [ ObjcMsgPattern ] 
	InferenceRule :  Template #_PatternType ObjcFunctionPattern 
	InferenceRule :  Template #_PatternType StringConstant 
	OptionalType : _    (123)

	(  shift 15
	.  reduce 123

	OptionalType  goto 24
	PatternType  goto 56

state 26
	Template :  TemplateType UnarySelector_    (87)

	.  reduce 87


state 27
	Template :  TemplateType BinarySelector_TemplateType 
	OptionalType : _    (123)

	(  shift 15
	.  reduce 123

	OptionalType  goto 14
	TemplateType  goto 57

state 28
	Template :  TemplateType KeywordPattern_    (89)
	KeywordPattern :  KeywordPattern_Keyword PatternType 

	KEYWORD  shift 48
	.  reduce 89

	Keyword  goto 58

state 29
	UnarySelector :  IDENTIFIER_    (127)

	.  reduce 127


state 30
	BinarySelector :  -_    (104)

	.  reduce 104


state 31
	BinarySelector :  SpecialCharacter_    (105)

	.  reduce 105


state 32
	BinarySelector :  DOUBLESPECIAL_    (106)

	.  reduce 106


state 33
	KeywordPattern :  Keyword_PatternType 
	OptionalType : _    (123)

	(  shift 15
	.  reduce 123

	OptionalType  goto 24
	PatternType  goto 59

state 34
	SpecialCharacter :  +_    (107)

	.  reduce 107


state 35
	SpecialCharacter :  /_    (108)

	.  reduce 108


state 36
	SpecialCharacter :  \\_    (109)

	.  reduce 109


state 37
	SpecialCharacter :  *_    (110)

	.  reduce 110


state 38
	SpecialCharacter :  ~_    (111)

	.  reduce 111


state 39
	SpecialCharacter :  <_    (112)

	.  reduce 112


state 40
	SpecialCharacter :  >_    (113)

	.  reduce 113


state 41
	SpecialCharacter :  =_    (114)

	.  reduce 114


state 42
	SpecialCharacter :  @_    (115)

	.  reduce 115


state 43
	SpecialCharacter :  %_    (116)

	.  reduce 116


state 44
	SpecialCharacter :  &_    (117)

	.  reduce 117


state 45
	SpecialCharacter :  ?_    (118)

	.  reduce 118


state 46
	SpecialCharacter :  ,_    (119)

	.  reduce 119


state 47
	SpecialCharacter :  |_    (120)

	.  reduce 120


state 48
	Keyword :  KEYWORD_    (132)

	.  reduce 132


state 49
	OptionalType :  ( Type_) 

	)  shift 60
	.  error


state 50
	Type :  IDENTIFIER_    (125)

	.  reduce 125


state 51
	Chunk :  VariableName KEYWORD # VariableName_KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant ! 

	KEYWORD  shift 61
	.  error


state 52
	Chunk :  VariableName KEYWORD STRING !_$$4 Methods Sep 
	$$4 : _    (4)

	.  reduce 4

	$$4  goto 62

state 53
	Chunk :  VariableName VariableName KEYWORD STRING_! $$6 Methods Sep 

	!  shift 63
	.  error


state 54
	InferenceRule :  # PatternType [_ObjcMsgPattern ] 
	OptionalType : _    (123)

	(  shift 15
	.  reduce 123

	ObjcMsgPattern  goto 64
	OptionalType  goto 24
	PatternType  goto 65

state 55
	InferenceRule :  # VariableName PatternType_VariableName 

	IDENTIFIER  shift 6
	.  error

	VariableName  goto 66

state 56
	InferenceRule :  Template # PatternType_[ ObjcMsgPattern ] 
	InferenceRule :  Template # PatternType_ObjcFunctionPattern 
	InferenceRule :  Template # PatternType_StringConstant 

	IDENTIFIER  shift 6
	STRING  shift 71
	[  shift 67
	.  error

	VariableName  goto 70
	ObjcFunctionPattern  goto 68
	StringConstant  goto 69

state 57
	Template :  TemplateType BinarySelector TemplateType_    (88)

	.  reduce 88


state 58
	KeywordPattern :  KeywordPattern Keyword_PatternType 
	OptionalType : _    (123)

	(  shift 15
	.  reduce 123

	OptionalType  goto 24
	PatternType  goto 72

state 59
	KeywordPattern :  Keyword PatternType_    (90)

	.  reduce 90


state 60
	OptionalType :  ( Type )_    (124)

	.  reduce 124


state 61
	Chunk :  VariableName KEYWORD # VariableName KEYWORD_StringConstant KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant ! 

	STRING  shift 71
	.  error

	StringConstant  goto 73

state 62
	Chunk :  VariableName KEYWORD STRING ! $$4_Methods Sep 
	Methods : _    (13)

	.  reduce 13

	Methods  goto 74

state 63
	Chunk :  VariableName VariableName KEYWORD STRING !_$$6 Methods Sep 
	$$6 : _    (6)

	.  reduce 6

	$$6  goto 75

state 64
	InferenceRule :  # PatternType [ ObjcMsgPattern_] 

	]  shift 76
	.  error


state 65
	ObjcMsgPattern :  PatternType_UnarySelector 
	ObjcMsgPattern :  PatternType_ObjcKeywordPattern 

	IDENTIFIER  shift 29
	KEYWORD  shift 48
	.  error

	Keyword  goto 79
	UnarySelector  goto 77
	ObjcKeywordPattern  goto 78

state 66
	InferenceRule :  # VariableName PatternType VariableName_    (86)

	.  reduce 86


state 67
	InferenceRule :  Template # PatternType [_ObjcMsgPattern ] 
	OptionalType : _    (123)

	(  shift 15
	.  reduce 123

	ObjcMsgPattern  goto 80
	OptionalType  goto 24
	PatternType  goto 65

state 68
	InferenceRule :  Template # PatternType ObjcFunctionPattern_    (84)

	.  reduce 84


state 69
	InferenceRule :  Template # PatternType StringConstant_    (85)

	.  reduce 85


state 70
	ObjcFunctionPattern :  VariableName_( ObjcFunctionArgList ) 
	ObjcFunctionPattern :  VariableName_( ) 

	(  shift 81
	.  error


state 71
	StringConstant :  STRING_    (131)

	.  reduce 131


state 72
	KeywordPattern :  KeywordPattern Keyword PatternType_    (91)

	.  reduce 91


state 73
	Chunk :  VariableName KEYWORD # VariableName KEYWORD StringConstant_KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant ! 

	KEYWORD  shift 82
	.  error


state 74
	Chunk :  VariableName KEYWORD STRING ! $$4 Methods_Sep 
	Methods :  Methods_Method ! 
	Methods :  Methods_error ! 

	error  shift 85
	IDENTIFIER  shift 29
	KEYWORD  shift 48
	DOUBLESPECIAL  shift 32
	%  shift 43
	|  shift 47
	&  shift 44
	?  shift 45
	!  shift 86
	,  shift 46
	+  shift 34
	-  shift 30
	/  shift 35
	\\  shift 36
	*  shift 37
	~  shift 38
	<  shift 39
	>  shift 40
	=  shift 41
	@  shift 42
	.  error

	Method  goto 84
	MethodName  goto 87
	Keyword  goto 91
	KwdMethodDecl  goto 90
	BinarySelector  goto 89
	UnarySelector  goto 88
	SpecialCharacter  goto 31
	Sep  goto 83

state 75
	Chunk :  VariableName VariableName KEYWORD STRING ! $$6_Methods Sep 
	Methods : _    (13)

	.  reduce 13

	Methods  goto 92

state 76
	InferenceRule :  # PatternType [ ObjcMsgPattern ]_    (82)

	.  reduce 82


state 77
	ObjcMsgPattern :  PatternType UnarySelector_    (96)

	.  reduce 96


state 78
	ObjcMsgPattern :  PatternType ObjcKeywordPattern_    (97)
	ObjcKeywordPattern :  ObjcKeywordPattern_Keyword PatternType ParameterDesignator 

	KEYWORD  shift 48
	.  reduce 97

	Keyword  goto 93

state 79
	ObjcKeywordPattern :  Keyword_PatternType ParameterDesignator 
	OptionalType : _    (123)

	(  shift 15
	.  reduce 123

	OptionalType  goto 24
	PatternType  goto 94

state 80
	InferenceRule :  Template # PatternType [ ObjcMsgPattern_] 

	]  shift 95
	.  error


state 81
	ObjcFunctionPattern :  VariableName (_ObjcFunctionArgList ) 
	ObjcFunctionPattern :  VariableName (_) 
	OptionalType : _    (123)

	(  shift 15
	)  shift 97
	.  reduce 123

	ObjcFunctionArgList  goto 96
	OptionalType  goto 24
	PatternType  goto 98

state 82
	Chunk :  VariableName KEYWORD # VariableName KEYWORD StringConstant KEYWORD_StringConstant KEYWORD StringConstant KEYWORD StringConstant ! 

	STRING  shift 71
	.  error

	StringConstant  goto 99

state 83
	Chunk :  VariableName KEYWORD STRING ! $$4 Methods Sep_    (5)
	Sep :  Sep_! 

	!  shift 100
	.  reduce 5


state 84
	Methods :  Methods Method_! 

	!  shift 101
	.  error


state 85
	Methods :  Methods error_! 

	!  shift 102
	.  error


state 86
	Sep :  !_    (11)

	.  reduce 11


state 87
	Method :  MethodName_LocalVariables $$16 PrimMarker StmtList 
	LocalVariables : _    (23)

	|  shift 104
	.  reduce 23

	LocalVariables  goto 103

state 88
	MethodName :  UnarySelector_    (18)

	.  reduce 18


state 89
	MethodName :  BinarySelector_VariableName 

	IDENTIFIER  shift 6
	.  error

	VariableName  goto 105

state 90
	MethodName :  KwdMethodDecl_    (20)
	KwdMethodDecl :  KwdMethodDecl_Keyword VariableName 

	KEYWORD  shift 48
	.  reduce 20

	Keyword  goto 106

state 91
	KwdMethodDecl :  Keyword_VariableName 

	IDENTIFIER  shift 6
	.  error

	VariableName  goto 107

state 92
	Chunk :  VariableName VariableName KEYWORD STRING ! $$6 Methods_Sep 
	Methods :  Methods_Method ! 
	Methods :  Methods_error ! 

	error  shift 85
	IDENTIFIER  shift 29
	KEYWORD  shift 48
	DOUBLESPECIAL  shift 32
	%  shift 43
	|  shift 47
	&  shift 44
	?  shift 45
	!  shift 86
	,  shift 46
	+  shift 34
	-  shift 30
	/  shift 35
	\\  shift 36
	*  shift 37
	~  shift 38
	<  shift 39
	>  shift 40
	=  shift 41
	@  shift 42
	.  error

	Method  goto 84
	MethodName  goto 87
	Keyword  goto 91
	KwdMethodDecl  goto 90
	BinarySelector  goto 89
	UnarySelector  goto 88
	SpecialCharacter  goto 31
	Sep  goto 108

state 93
	ObjcKeywordPattern :  ObjcKeywordPattern Keyword_PatternType ParameterDesignator 
	OptionalType : _    (123)

	(  shift 15
	.  reduce 123

	OptionalType  goto 24
	PatternType  goto 109

state 94
	ObjcKeywordPattern :  Keyword PatternType_ParameterDesignator 

	IDENTIFIER  shift 6
	%  shift 112
	.  error

	VariableName  goto 111
	ParameterDesignator  goto 110

state 95
	InferenceRule :  Template # PatternType [ ObjcMsgPattern ]_    (83)

	.  reduce 83


state 96
	ObjcFunctionPattern :  VariableName ( ObjcFunctionArgList_) 
	ObjcFunctionArgList :  ObjcFunctionArgList_, PatternType ParameterDesignator 

	,  shift 114
	)  shift 113
	.  error


state 97
	ObjcFunctionPattern :  VariableName ( )_    (93)

	.  reduce 93


state 98
	ObjcFunctionArgList :  PatternType_ParameterDesignator 

	IDENTIFIER  shift 6
	%  shift 112
	.  error

	VariableName  goto 111
	ParameterDesignator  goto 115

state 99
	Chunk :  VariableName KEYWORD # VariableName KEYWORD StringConstant KEYWORD StringConstant_KEYWORD StringConstant KEYWORD StringConstant ! 

	KEYWORD  shift 116
	.  error


state 100
	Sep :  Sep !_    (12)

	.  reduce 12


state 101
	Methods :  Methods Method !_    (14)

	.  reduce 14


state 102
	Methods :  Methods error !_    (15)

	.  reduce 15


state 103
	Method :  MethodName LocalVariables_$$16 PrimMarker StmtList 
	$$16 : _    (16)

	.  reduce 16

	$$16  goto 117

state 104
	LocalVariables :  |_VarList | 
	VarList : _    (25)

	.  reduce 25

	VarList  goto 118

state 105
	MethodName :  BinarySelector VariableName_    (19)

	.  reduce 19


state 106
	KwdMethodDecl :  KwdMethodDecl Keyword_VariableName 

	IDENTIFIER  shift 6
	.  error

	VariableName  goto 119

state 107
	KwdMethodDecl :  Keyword VariableName_    (27)

	.  reduce 27


state 108
	Chunk :  VariableName VariableName KEYWORD STRING ! $$6 Methods Sep_    (7)
	Sep :  Sep_! 

	!  shift 100
	.  reduce 7


state 109
	ObjcKeywordPattern :  ObjcKeywordPattern Keyword PatternType_ParameterDesignator 

	IDENTIFIER  shift 6
	%  shift 112
	.  error

	VariableName  goto 111
	ParameterDesignator  goto 120

state 110
	ObjcKeywordPattern :  Keyword PatternType ParameterDesignator_    (98)

	.  reduce 98


state 111
	ParameterDesignator :  VariableName_    (100)

	.  reduce 100


state 112
	ParameterDesignator :  %_DIGITS 

	DIGITS  shift 121
	.  error


state 113
	ObjcFunctionPattern :  VariableName ( ObjcFunctionArgList )_    (92)

	.  reduce 92


state 114
	ObjcFunctionArgList :  ObjcFunctionArgList ,_PatternType ParameterDesignator 
	OptionalType : _    (123)

	(  shift 15
	.  reduce 123

	OptionalType  goto 24
	PatternType  goto 122

state 115
	ObjcFunctionArgList :  PatternType ParameterDesignator_    (94)

	.  reduce 94


state 116
	Chunk :  VariableName KEYWORD # VariableName KEYWORD StringConstant KEYWORD StringConstant KEYWORD_StringConstant KEYWORD StringConstant ! 

	STRING  shift 71
	.  error

	StringConstant  goto 123

state 117
	Method :  MethodName LocalVariables $$16_PrimMarker StmtList 
	PrimMarker : _    (21)

	<  shift 125
	.  reduce 21

	PrimMarker  goto 124

state 118
	LocalVariables :  | VarList_| 
	VarList :  VarList_VariableName 

	IDENTIFIER  shift 6
	|  shift 126
	.  error

	VariableName  goto 127

state 119
	KwdMethodDecl :  KwdMethodDecl Keyword VariableName_    (28)

	.  reduce 28


state 120
	ObjcKeywordPattern :  ObjcKeywordPattern Keyword PatternType ParameterDesignator_    (99)

	.  reduce 99


state 121
	ParameterDesignator :  % DIGITS_    (101)

	.  reduce 101


state 122
	ObjcFunctionArgList :  ObjcFunctionArgList , PatternType_ParameterDesignator 

	IDENTIFIER  shift 6
	%  shift 112
	.  error

	VariableName  goto 111
	ParameterDesignator  goto 128

state 123
	Chunk :  VariableName KEYWORD # VariableName KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant_KEYWORD StringConstant ! 

	KEYWORD  shift 129
	.  error


state 124
	Method :  MethodName LocalVariables $$16 PrimMarker_StmtList 
	AssignmentList : _    (37)

	error  shift 133
	^  shift 131
	.  reduce 37

	StmtList  goto 130
	Expr  goto 132
	AssignmentList  goto 134

state 125
	PrimMarker :  <_KEYWORD NumberConstant > 

	KEYWORD  shift 135
	.  error


state 126
	LocalVariables :  | VarList |_    (24)

	.  reduce 24


state 127
	VarList :  VarList VariableName_    (26)

	.  reduce 26


state 128
	ObjcFunctionArgList :  ObjcFunctionArgList , PatternType ParameterDesignator_    (95)

	.  reduce 95


state 129
	Chunk :  VariableName KEYWORD # VariableName KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant KEYWORD_StringConstant ! 

	STRING  shift 71
	.  error

	StringConstant  goto 136

state 130
	Method :  MethodName LocalVariables $$16 PrimMarker StmtList_    (17)

	.  reduce 17


state 131
	StmtList :  ^_Expr 
	AssignmentList : _    (37)

	.  reduce 37

	Expr  goto 137
	AssignmentList  goto 134

state 132
	StmtList :  Expr_    (30)
	StmtList :  Expr_. 
	StmtList :  Expr_. StmtList 

	.  shift 138
	.  reduce 30


state 133
	StmtList :  error_. 

	.  shift 139
	.  error


state 134
	Expr :  AssignmentList_Primary 
	Expr :  AssignmentList_SimpleMsgExpr 
	Expr :  AssignmentList_SimpleMsgExpr CascadedMsgExpr 
	AssignmentList :  AssignmentList_VariableName _ 

	IDENTIFIER  shift 6
	DIGITS  shift 157
	STRING  shift 71
	CHARCON  shift 156
	#  shift 152
	-  shift 158
	(  shift 145
	[  shift 153
	.  error

	Primary  goto 140
	UnaryObjDesc  goto 154
	BinaryObjDesc  goto 155
	SimpleMsgExpr  goto 141
	UnaryExpr  goto 146
	BinaryExpr  goto 147
	KeywordExpr  goto 148
	Literal  goto 143
	Block  goto 144
	VariableName  goto 142
	CharacterConstant  goto 149
	NumberConstant  goto 151
	StringConstant  goto 150

state 135
	PrimMarker :  < KEYWORD_NumberConstant > 

	DIGITS  shift 157
	-  shift 158
	.  error

	NumberConstant  goto 159

state 136
	Chunk :  VariableName KEYWORD # VariableName KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant_! 

	!  shift 160
	.  error


state 137
	StmtList :  ^ Expr_    (29)

	.  reduce 29


state 138
	StmtList :  Expr ._    (31)
	StmtList :  Expr ._StmtList 
	AssignmentList : _    (37)

	error  shift 133
	!  reduce 31
	^  shift 131
	]  reduce 31
	.  reduce 37

	StmtList  goto 161
	Expr  goto 132
	AssignmentList  goto 134

state 139
	StmtList :  error ._    (33)

	.  reduce 33


state 140
	Expr :  AssignmentList Primary_    (34)
	UnaryObjDesc :  Primary_    (51)

	!  reduce 34
	.  reduce 34
	)  reduce 34
	]  reduce 34
	.  reduce 51


state 141
	Expr :  AssignmentList SimpleMsgExpr_    (35)
	Expr :  AssignmentList SimpleMsgExpr_CascadedMsgExpr 

	;  shift 164
	.  reduce 35

	CascadedMsgExpr  goto 162
	CascadedMsg  goto 163

state 142
	AssignmentList :  AssignmentList VariableName__ 
	Primary :  VariableName_    (44)

	_  shift 165
	.  reduce 44


state 143
	Primary :  Literal_    (45)

	.  reduce 45


state 144
	Primary :  Block_    (46)

	.  reduce 46


state 145
	Primary :  (_Expr ) 
	AssignmentList : _    (37)

	.  reduce 37

	Expr  goto 166
	AssignmentList  goto 134

state 146
	SimpleMsgExpr :  UnaryExpr_    (48)
	UnaryObjDesc :  UnaryExpr_    (52)

	!  reduce 48
	.  reduce 48
	;  reduce 48
	)  reduce 48
	]  reduce 48
	.  reduce 52


state 147
	SimpleMsgExpr :  BinaryExpr_    (49)
	BinaryObjDesc :  BinaryExpr_    (55)

	!  reduce 49
	.  reduce 49
	;  reduce 49
	)  reduce 49
	]  reduce 49
	.  reduce 55


state 148
	SimpleMsgExpr :  KeywordExpr_    (50)

	.  reduce 50


state 149
	Literal :  CharacterConstant_    (60)

	.  reduce 60


state 150
	Literal :  StringConstant_    (61)

	.  reduce 61


state 151
	Literal :  NumberConstant_    (62)

	.  reduce 62


state 152
	Literal :  #_( ArrayMemberList ) 
	Literal :  #_UnarySelector 
	Literal :  #_BinarySelector 
	Literal :  #_KeywordList 

	IDENTIFIER  shift 29
	KEYWORD  shift 171
	DOUBLESPECIAL  shift 32
	%  shift 43
	|  shift 47
	&  shift 44
	?  shift 45
	,  shift 46
	+  shift 34
	-  shift 30
	/  shift 35
	\\  shift 36
	*  shift 37
	~  shift 38
	<  shift 39
	>  shift 40
	=  shift 41
	@  shift 42
	(  shift 167
	.  error

	BinarySelector  goto 169
	UnarySelector  goto 168
	KeywordList  goto 170
	SpecialCharacter  goto 31

state 153
	Block :  [_BlockVariables StmtList ] 
	Block :  [_BlockVariables ] 
	BlockVariables : _    (78)

	:  shift 174
	.  reduce 78

	BlockVarList  goto 173
	BlockVariables  goto 172

state 154
	UnaryExpr :  UnaryObjDesc_UnarySelector 
	BinaryObjDesc :  UnaryObjDesc_    (54)

	IDENTIFIER  shift 29
	.  reduce 54

	UnarySelector  goto 175

state 155
	BinaryExpr :  BinaryObjDesc_BinarySelector UnaryObjDesc 
	KeywordExpr :  BinaryObjDesc_KeywordArgList 

	KEYWORD  shift 48
	DOUBLESPECIAL  shift 32
	%  shift 43
	|  shift 47
	&  shift 44
	?  shift 45
	,  shift 46
	+  shift 34
	-  shift 30
	/  shift 35
	\\  shift 36
	*  shift 37
	~  shift 38
	<  shift 39
	>  shift 40
	=  shift 41
	@  shift 42
	.  error

	Keyword  goto 178
	KeywordArgList  goto 177
	BinarySelector  goto 176
	SpecialCharacter  goto 31

state 156
	CharacterConstant :  CHARCON_    (128)

	.  reduce 128


state 157
	NumberConstant :  DIGITS_    (129)

	.  reduce 129


state 158
	NumberConstant :  -_DIGITS 

	DIGITS  shift 179
	.  error


state 159
	PrimMarker :  < KEYWORD NumberConstant_> 

	>  shift 180
	.  error


state 160
	Chunk :  VariableName KEYWORD # VariableName KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant KEYWORD StringConstant !_    (3)

	.  reduce 3


state 161
	StmtList :  Expr . StmtList_    (32)

	.  reduce 32


state 162
	Expr :  AssignmentList SimpleMsgExpr CascadedMsgExpr_    (36)
	CascadedMsgExpr :  CascadedMsgExpr_CascadedMsg 

	;  shift 164
	.  reduce 36

	CascadedMsg  goto 181

state 163
	CascadedMsgExpr :  CascadedMsg_    (39)

	.  reduce 39


state 164
	CascadedMsg :  ;_UnarySelector 
	CascadedMsg :  ;_BinarySelector UnaryObjDesc 
	CascadedMsg :  ;_KeywordArgList 

	IDENTIFIER  shift 29
	KEYWORD  shift 48
	DOUBLESPECIAL  shift 32
	%  shift 43
	|  shift 47
	&  shift 44
	?  shift 45
	,  shift 46
	+  shift 34
	-  shift 30
	/  shift 35
	\\  shift 36
	*  shift 37
	~  shift 38
	<  shift 39
	>  shift 40
	=  shift 41
	@  shift 42
	.  error

	Keyword  goto 178
	KeywordArgList  goto 184
	BinarySelector  goto 183
	UnarySelector  goto 182
	SpecialCharacter  goto 31

state 165
	AssignmentList :  AssignmentList VariableName __    (38)

	.  reduce 38


state 166
	Primary :  ( Expr_) 

	)  shift 185
	.  error


state 167
	Literal :  # (_ArrayMemberList ) 
	ArrayMemberList : _    (67)

	.  reduce 67

	ArrayMemberList  goto 186

state 168
	Literal :  # UnarySelector_    (64)

	.  reduce 64


state 169
	Literal :  # BinarySelector_    (65)

	.  reduce 65


170: shift/reduce conflict (shift 187, red'n 66) on KEYWORD
state 170
	Literal :  # KeywordList_    (66)
	KeywordList :  KeywordList_KEYWORD 

	KEYWORD  shift 187
	.  reduce 66


state 171
	KeywordList :  KEYWORD_    (102)

	.  reduce 102


state 172
	Block :  [ BlockVariables_StmtList ] 
	Block :  [ BlockVariables_] 
	AssignmentList : _    (37)

	error  shift 133
	^  shift 131
	]  shift 189
	.  reduce 37

	StmtList  goto 188
	Expr  goto 132
	AssignmentList  goto 134

state 173
	BlockVariables :  BlockVarList_| 
	BlockVarList :  BlockVarList_: VariableName 

	|  shift 190
	:  shift 191
	.  error


state 174
	BlockVarList :  :_VariableName 

	IDENTIFIER  shift 6
	.  error

	VariableName  goto 192

state 175
	UnaryExpr :  UnaryObjDesc UnarySelector_    (53)

	.  reduce 53


state 176
	BinaryExpr :  BinaryObjDesc BinarySelector_UnaryObjDesc 

	IDENTIFIER  shift 6
	DIGITS  shift 157
	STRING  shift 71
	CHARCON  shift 156
	#  shift 152
	-  shift 158
	(  shift 145
	[  shift 153
	.  error

	Primary  goto 194
	UnaryObjDesc  goto 193
	UnaryExpr  goto 195
	Literal  goto 143
	Block  goto 144
	VariableName  goto 196
	CharacterConstant  goto 149
	NumberConstant  goto 151
	StringConstant  goto 150

state 177
	KeywordExpr :  BinaryObjDesc KeywordArgList_    (57)
	KeywordArgList :  KeywordArgList_Keyword BinaryObjDesc 

	KEYWORD  shift 48
	.  reduce 57

	Keyword  goto 197

state 178
	KeywordArgList :  Keyword_BinaryObjDesc 

	IDENTIFIER  shift 6
	DIGITS  shift 157
	STRING  shift 71
	CHARCON  shift 156
	#  shift 152
	-  shift 158
	(  shift 145
	[  shift 153
	.  error

	Primary  goto 194
	UnaryObjDesc  goto 154
	BinaryObjDesc  goto 198
	UnaryExpr  goto 195
	BinaryExpr  goto 199
	Literal  goto 143
	Block  goto 144
	VariableName  goto 196
	CharacterConstant  goto 149
	NumberConstant  goto 151
	StringConstant  goto 150

state 179
	NumberConstant :  - DIGITS_    (130)

	.  reduce 130


state 180
	PrimMarker :  < KEYWORD NumberConstant >_    (22)

	.  reduce 22


state 181
	CascadedMsgExpr :  CascadedMsgExpr CascadedMsg_    (40)

	.  reduce 40


state 182
	CascadedMsg :  ; UnarySelector_    (41)

	.  reduce 41


state 183
	CascadedMsg :  ; BinarySelector_UnaryObjDesc 

	IDENTIFIER  shift 6
	DIGITS  shift 157
	STRING  shift 71
	CHARCON  shift 156
	#  shift 152
	-  shift 158
	(  shift 145
	[  shift 153
	.  error

	Primary  goto 194
	UnaryObjDesc  goto 200
	UnaryExpr  goto 195
	Literal  goto 143
	Block  goto 144
	VariableName  goto 196
	CharacterConstant  goto 149
	NumberConstant  goto 151
	StringConstant  goto 150

state 184
	CascadedMsg :  ; KeywordArgList_    (43)
	KeywordArgList :  KeywordArgList_Keyword BinaryObjDesc 

	KEYWORD  shift 48
	.  reduce 43

	Keyword  goto 197

state 185
	Primary :  ( Expr )_    (47)

	.  reduce 47


state 186
	Literal :  # ( ArrayMemberList_) 
	ArrayMemberList :  ArrayMemberList_ArrayMember 

	IDENTIFIER  shift 29
	DIGITS  shift 157
	KEYWORD  shift 171
	STRING  shift 71
	CHARCON  shift 156
	DOUBLESPECIAL  shift 32
	%  shift 43
	|  shift 47
	&  shift 44
	?  shift 45
	,  shift 46
	+  shift 34
	-  shift 210
	/  shift 35
	\\  shift 36
	*  shift 37
	~  shift 38
	<  shift 39
	>  shift 40
	=  shift 41
	@  shift 42
	(  shift 209
	)  shift 201
	.  error

	ArrayMember  goto 202
	BinarySelector  goto 207
	UnarySelector  goto 206
	KeywordList  goto 208
	CharacterConstant  goto 203
	NumberConstant  goto 205
	StringConstant  goto 204
	SpecialCharacter  goto 31

state 187
	KeywordList :  KeywordList KEYWORD_    (103)

	.  reduce 103


state 188
	Block :  [ BlockVariables StmtList_] 

	]  shift 211
	.  error


state 189
	Block :  [ BlockVariables ]_    (77)

	.  reduce 77


state 190
	BlockVariables :  BlockVarList |_    (79)

	.  reduce 79


state 191
	BlockVarList :  BlockVarList :_VariableName 

	IDENTIFIER  shift 6
	.  error

	VariableName  goto 212

state 192
	BlockVarList :  : VariableName_    (80)

	.  reduce 80


state 193
	UnaryExpr :  UnaryObjDesc_UnarySelector 
	BinaryExpr :  BinaryObjDesc BinarySelector UnaryObjDesc_    (56)

	IDENTIFIER  shift 29
	.  reduce 56

	UnarySelector  goto 175

state 194
	UnaryObjDesc :  Primary_    (51)

	.  reduce 51


state 195
	UnaryObjDesc :  UnaryExpr_    (52)

	.  reduce 52


state 196
	Primary :  VariableName_    (44)

	.  reduce 44


state 197
	KeywordArgList :  KeywordArgList Keyword_BinaryObjDesc 

	IDENTIFIER  shift 6
	DIGITS  shift 157
	STRING  shift 71
	CHARCON  shift 156
	#  shift 152
	-  shift 158
	(  shift 145
	[  shift 153
	.  error

	Primary  goto 194
	UnaryObjDesc  goto 154
	BinaryObjDesc  goto 213
	UnaryExpr  goto 195
	BinaryExpr  goto 199
	Literal  goto 143
	Block  goto 144
	VariableName  goto 196
	CharacterConstant  goto 149
	NumberConstant  goto 151
	StringConstant  goto 150

state 198
	BinaryExpr :  BinaryObjDesc_BinarySelector UnaryObjDesc 
	KeywordArgList :  Keyword BinaryObjDesc_    (58)

	DOUBLESPECIAL  shift 32
	%  shift 43
	|  shift 47
	&  shift 44
	?  shift 45
	,  shift 46
	+  shift 34
	-  shift 30
	/  shift 35
	\\  shift 36
	*  shift 37
	~  shift 38
	<  shift 39
	>  shift 40
	=  shift 41
	@  shift 42
	.  reduce 58

	BinarySelector  goto 176
	SpecialCharacter  goto 31

state 199
	BinaryObjDesc :  BinaryExpr_    (55)

	.  reduce 55


state 200
	CascadedMsg :  ; BinarySelector UnaryObjDesc_    (42)
	UnaryExpr :  UnaryObjDesc_UnarySelector 

	IDENTIFIER  shift 29
	.  reduce 42

	UnarySelector  goto 175

state 201
	Literal :  # ( ArrayMemberList )_    (63)

	.  reduce 63


state 202
	ArrayMemberList :  ArrayMemberList ArrayMember_    (68)

	.  reduce 68


state 203
	ArrayMember :  CharacterConstant_    (69)

	.  reduce 69


state 204
	ArrayMember :  StringConstant_    (70)

	.  reduce 70


state 205
	ArrayMember :  NumberConstant_    (71)

	.  reduce 71


state 206
	ArrayMember :  UnarySelector_    (72)

	.  reduce 72


state 207
	ArrayMember :  BinarySelector_    (73)

	.  reduce 73


208: shift/reduce conflict (shift 187, red'n 74) on KEYWORD
state 208
	ArrayMember :  KeywordList_    (74)
	KeywordList :  KeywordList_KEYWORD 

	KEYWORD  shift 187
	.  reduce 74


state 209
	ArrayMember :  (_ArrayMemberList ) 
	ArrayMemberList : _    (67)

	.  reduce 67

	ArrayMemberList  goto 214

210: shift/reduce conflict (shift 179, red'n 104) on DIGITS
state 210
	BinarySelector :  -_    (104)
	NumberConstant :  -_DIGITS 

	DIGITS  shift 179
	.  reduce 104


state 211
	Block :  [ BlockVariables StmtList ]_    (76)

	.  reduce 76


state 212
	BlockVarList :  BlockVarList : VariableName_    (81)

	.  reduce 81


state 213
	BinaryExpr :  BinaryObjDesc_BinarySelector UnaryObjDesc 
	KeywordArgList :  KeywordArgList Keyword BinaryObjDesc_    (59)

	DOUBLESPECIAL  shift 32
	%  shift 43
	|  shift 47
	&  shift 44
	?  shift 45
	,  shift 46
	+  shift 34
	-  shift 30
	/  shift 35
	\\  shift 36
	*  shift 37
	~  shift 38
	<  shift 39
	>  shift 40
	=  shift 41
	@  shift 42
	.  reduce 59

	BinarySelector  goto 176
	SpecialCharacter  goto 31

state 214
	ArrayMemberList :  ArrayMemberList_ArrayMember 
	ArrayMember :  ( ArrayMemberList_) 

	IDENTIFIER  shift 29
	DIGITS  shift 157
	KEYWORD  shift 171
	STRING  shift 71
	CHARCON  shift 156
	DOUBLESPECIAL  shift 32
	%  shift 43
	|  shift 47
	&  shift 44
	?  shift 45
	,  shift 46
	+  shift 34
	-  shift 210
	/  shift 35
	\\  shift 36
	*  shift 37
	~  shift 38
	<  shift 39
	>  shift 40
	=  shift 41
	@  shift 42
	(  shift 209
	)  shift 215
	.  error

	ArrayMember  goto 202
	BinarySelector  goto 207
	UnarySelector  goto 206
	KeywordList  goto 208
	CharacterConstant  goto 203
	NumberConstant  goto 205
	StringConstant  goto 204
	SpecialCharacter  goto 31

state 215
	ArrayMember :  ( ArrayMemberList )_    (75)

	.  reduce 75


37/300 terminals, 53/300 nonterminals
133/600 grammar rules, 216/750 states
3 shift/reduce, 0 reduce/reduce conflicts reported
53/350 working sets used
memory: states,etc. 1089/24000, parser 269/12000
109/600 distinct lookahead sets
179 extra closures
341 shift entries, 17 exceptions
139 goto entries
68 entries saved by goto default
Optimizer space used: input 909/24000, output 501/12000
501 table entries, 143 zero
maximum spread: 262, maximum offset: 260
\Rogue\Monster\
else
  echo "will not over write ./src/y.output"
fi
echo "Finished archive 3 of 5"
exit
----
Dieter H. Zebbedies ('dee-ter  ayech  'zeb-ed-eez)
 Zebb-Hoff Mach. Tool's Automated Manufacturing Project Cleveland, OH
 (USnail): 9535 Clinton Rd, Cleveland, OH 44144 (+216 631 6100) (+216 741-5994)
 (UUCP): ...{decvax,sun,cbosgd}!cwruecmp!zhmti!dieter
 (CSNET/ARPA/BITNET): dieter@CWRU.EDU

dietz@zhmti.UUCP (Dieter H. Zebbedies) (08/20/87)

"Producer", A package to translate Smalltalk-80 code to your favorite
object oriented language, Objective-C.

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -d ./src`
then
  mkdir ./src
  echo "mkdir ./src"
fi
if `test ! -s ./src/Substrate.h`
then
echo "writting ./src/Substrate.h"
cat > ./src/Substrate.h << '\Rogue\Monster\'
/*{^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Substrate.h: Extensions to the Objective-C Primitive and Collection substrate
	The macros hide nonPortable `features' of some C compilers (e.g. VMS).
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^}*/
#ifndef SUBSTRATE_H
#define SUBSTRATE_H
#	include "objc.h"
#	include "assert.h"
#	undef CATEGORIES
#	define CATEGORIES() (Substrate, Primitive)

/*{ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Stylistic Conventions
	The IMPORT/EXPORT convention (EXPORT int foo=aValue to export foo,
	IMPORT int foo to import it) is used instead of of the usual C 
	conventions (int foo=aValue to export foo and extern int foo to 
	import it) to provides a distinctive marker on each global declaration
	that string search tools key off of to find all global declarations 
	reliably. The convention also provides a convenient way to overcome
	deficiencies in some C compilers; notably VMS C.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }*/
#	define LOCAL static
#	define USE @requires
#ifdef VMS
#	define IMPORT globalref
#	define EXPORT globaldef
#else
#	define IMPORT extern
#	define EXPORT /*export*/
#endif
// Obsolete
#	define FACTORY USE

/*{ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Renaming
	Translate all occurrences of external names that appear in the Primitive
	or Collection categories to new names defined in the Substrate category.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }*/
#define OrderedCollection OrdCltn

/*{ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Bit banging macros
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }*/
#	define RBIT(bits, mask)	(bits &= ~mask)
#	define SBIT(bits, mask)	(bits |=  mask)
#	define TBIT(bits, mask) (bits &   mask)

	typedef int *WORD;			/* Amorphous typed machine word */
	typedef unsigned int WRD;	/* amorphous type; `word' */
	typedef char BYTE;
	unsigned _strhash();
	IMPORT void put();
#endif
\Rogue\Monster\
else
  echo "will not over write ./src/Substrate.h"
fi
if `test ! -s ./src/AbstractTranslation.m`
then
echo "writting ./src/AbstractTranslation.m"
cat > ./src/AbstractTranslation.m << '\Rogue\Monster\'
#include "Producer.h"
= AbstractTranslation : Object CATEGORIES()
	{ id type; }
+ type:aType 
	{ return [[self new] type:aType]; }
- type 
	{ return type; }
- type:aType
	{ type = aType; return self; }
- (STR)str
	{ return (STR)[self subclassResponsibility]; }
- asTypedByteArray
	{ return (id)[self subclassResponsibility]; }
- assignTypesTo:aSelector {
	id s = [aSelector asByteArray];
	info("%s ignoring type assignment of %s\n", NAMEOF(self), [s str]);
	[s free]; return self;
}
\Rogue\Monster\
else
  echo "will not over write ./src/AbstractTranslation.m"
fi
if `test ! -s ./src/ArgumentList.m`
then
echo "writting ./src/ArgumentList.m"
cat > ./src/ArgumentList.m << '\Rogue\Monster\'
#include "Producer.h"
= ArgumentList:Node CATEGORIES()
	{ id argumentType, argumentName; }
+ type:aType name:aName {
	self = [super new];
	argumentType = aType;
	argumentName = aName;
	return self;
}
- argumentType
	{ return argumentType; }
- argumentName
	{ return argumentName; }
\Rogue\Monster\
else
  echo "will not over write ./src/ArgumentList.m"
fi
if `test ! -s ./src/Block.m`
then
echo "writting ./src/Block.m"
cat > ./src/Block.m << '\Rogue\Monster\'
#include "Producer.h"
	IMPORT id symbolScope;
	USE Set;
= Block:Node CATEGORIES() { id blockVariables, statements; }
+ statements:aStatementList 
	{ return [[self new] statements:aStatementList]; }
- variables:aVarList { 
	if (!aVarList || [aVarList isEmpty]) return self;
	[aVarList addContentsTo:blockVariables = [Set new]];
	[symbolScope add:blockVariables];
	return self; 
}
- statements:aStatementList 
	{ statements = aStatementList; return self; }

- gen { BOOL needsCompound = blockVariables || [statements size] > 1;
	if (needsCompound) gc('{'/*}*/);
#ifndef COXLIB
	[blockVariables elementsPerform:@selector(genDeclaration)];
#else
	[blockVariables eachElementPerform:@selector(genDeclaration)];
#endif
	[statements genExpr];
	if (needsCompound) gc(/*{*/'}');
	return self; 
}
- free { 
	[symbolScope remove:blockVariables];
	[blockVariables freeContents]; [blockVariables free];
	[statements free];
	return [super free];
}
- type 
	{ [statements type]; return types.BLOCK; }
\Rogue\Monster\
else
  echo "will not over write ./src/Block.m"
fi
if `test ! -s ./src/CharConstant.m`
then
echo "writting ./src/CharConstant.m"
cat > ./src/CharConstant.m << '\Rogue\Monster\'
#include "Producer.h"
= CharConstant : Constant CATEGORIES() {}
- type
	{ return types.CHAR; }
- gen
	{ gf("'%s'", [self str]); return self; }
\Rogue\Monster\
else
  echo "will not over write ./src/CharConstant.m"
fi
if `test ! -s ./src/Class.m`
then
echo "writting ./src/Class.m"
cat > ./src/Class.m << '\Rogue\Monster\'
#include "Producer.h"
	BOOL autoFileFlag;
	USE OrderedCollection, Identifier;
	IMPORT id symbolScope;
	IMPORT STR index();
	IMPORT id findSymbol();
= Class:Object CATEGORIES() {
	id name, superclass, instanceVariables, classVariables, pdn, category;
	id instanceVariableScope, classVariableScope;
}
+ name:aClass { self = [super new]; name = aClass; 
	if (autoFileFlag) { char buf[80];
		sprintf(buf, "%s.m", [name str]);
		genOpen(buf);
	}
	return self; 
}
- superclass:aClass { superclass = aClass; return self; }
- instanceVariableNames:aString { STR s = [aString str], end;
	if (!instanceVariables) instanceVariables = [OrderedCollection new];
	if (*s == '\'') s++;
	while(end = index(s, ' ')) { 
		while(*end == ' ') *end++ = 0;
		[instanceVariables add:findSymbol([Identifier str:s])];
		s = end;
	}
	if (end = index(s, '\'')) { *end = 0;
		[instanceVariables add:findSymbol([Identifier str:s])];
	}
	[symbolScope add:instanceVariableScope=[instanceVariables asSet]];
	return self; 
}
- classVariableNames:aString { STR s = [aString str], end;
	if (!classVariables) classVariables = [OrderedCollection new];
	if (*s == '\'') s++;
	while(end = index(s, ' ')) { 
		while(*end == ' ') *end++ = 0;
		[classVariables add:findSymbol([Identifier str:s])];
		s = end;
	}
	if (end = index(s, '\'')) { *end = 0;
		[instanceVariables add:findSymbol([Identifier str:s])];
	}
	[symbolScope add:classVariableScope=[classVariables asSet]];
	return self; 
}
- poolDictionaries:aString { pdn = aString; return self; }
- category:aString { category = aString; return self; }
- gen { STR start, end, index(); 
	gn(); gs("#include \"st80.h\"\n");
	gs("= "); [name gen]; gc(':'); [superclass gen]; gs(" CATEGORIES()");
	gc('{'/*}*/);
#ifndef COXLIB
	[instanceVariables elementsPerform:@selector(genDeclaration)];
	gc(/*{*/'}');
	if (classVariables) 
		[classVariables elementsPerform:@selector(genDeclaration)];
#else
	[instanceVariables eachElementPerform:@selector(genDeclaration)];
	gc(/*{*/'}');
	if (classVariables) 
		[classVariables eachElementPerform:@selector(genDeclaration)];
#endif
	return self;
}
- free {
	[symbolScope remove:instanceVariableScope];
	[symbolScope remove:classVariableScope];
	[classVariables freeContents]; [instanceVariables freeContents];
	[classVariables free]; [instanceVariables free];
	[name free];
	[superclass free];
	[pdn free];
	[category free];
	return [super free];
}
\Rogue\Monster\
else
  echo "will not over write ./src/Class.m"
fi
if `test ! -s ./src/Comment.m`
then
echo "writting ./src/Comment.m"
cat > ./src/Comment.m << '\Rogue\Monster\'
#include "Producer.h"
	static id head = nil, tail = nil;
	BOOL stripCommentsFlag = YES;
= Comment:Node CATEGORIES() { STR text; }
+ str:(STR)aString { 
	if (!aString) return nil;
	self = [super new]; text = (STR)strCopy(aString);
	if (head == nil) head = self; else tail->successor = self;
	return tail = self;
}
+ gen { genReset(); [head gen];
	[head free]; head = tail = nil;
	return self; 
}
+ free 
	{ if (head) [head free]; head = tail = nil; return self; }
- (STR)str 
	{ return text; }
- free 
	{ free(text); return [super free]; }
- gen { 
	if (!stripCommentsFlag) { gf("// %s", text); [successor gen]; }
	return self; 
}
\Rogue\Monster\
else
  echo "will not over write ./src/Comment.m"
fi
if `test ! -s ./src/Constant.m`
then
echo "writting ./src/Constant.m"
cat > ./src/Constant.m << '\Rogue\Monster\'
#include "Producer.h"
= Constant:Symbol CATEGORIES()
- gen 
	{ gs([self str]); return self; }
- type
	{ return [self subclassResponsibility]; }
- asByteArray
	{ return self; }
\Rogue\Monster\
else
  echo "will not over write ./src/Constant.m"
fi
if `test ! -s ./src/Expr.m`
then
echo "writting ./src/Expr.m"
cat > ./src/Expr.m << '\Rogue\Monster\'
// Expressions: a source (a message or primary) for a value and a list of 
//	targets (variables) to assign values to. Cascaded message expressions 
//	are handled by linking expressions through their successor fields.
//
// Rewrites cascaded expressions like 
//		Foo new bar gag extent:hack; bletch.
//	as 
//		cascadeReceiver = [[[Foo new] bar] gag].
//		[cascadeReceiver extent:hack];
//		[cascadeReceiver ...
#include "Producer.h"
	IMPORT id temporaryVariablePool;
	USE Msg, List, Identifier;
= Expr:Node CATEGORIES() {
	id assignmentList;
	id value;
}
+ assign:anAssignmentList value:aValue 
	{ return [[[super new] assign:anAssignmentList] value:aValue]; }
- assign:aList
	{ assignmentList = aList; return self; }
- value:aValue
	{ if (value) info("value of %s reassigned\n", NAMEOF(self));
	value = aValue; return self; }
- value
	{ return value; }
- gen { 
	if (assignmentList) { id s, v;
		for (s = [assignmentList eachElement]; v = [s next]; ) 
			{ [v gen]; gs(" = "); }
		[s free];
	}
	[value gen]; 
	if (successor) { gc(';'); [successor gen]; }
	return self; 
}
- type { id type = [value type]; 
	if (successor) [successor type];
#ifndef COXLIB
	if (assignmentList)
		[assignmentList elementsPerform:@selector(type:rule:)
			with:type with:"value assignment"];
#else
	if (assignmentList)
		[assignmentList eachElementPerform:@selector(type:rule:)
			with:type with:"value assignment"];
#endif
	return type;
}
- cascade:anExpr { 
	id newReceiver = [Identifier uniqueIdentifier:"tmp"];
	if ([value isKindOf:Msg]) { 
		id newValue = [Msg receiver:newReceiver selector:[value selector]];
		id newExpr = [Expr assign:assignmentList value:newValue];
		value = [value receiver];
		assignmentList = [List with:1, newReceiver];
		[self successor:newExpr]; [newExpr successor:anExpr];
		do { id msg = [newExpr value];
			if ([msg isKindOf:Msg]) [msg receiver:newReceiver]; 
		} while (newExpr = [newExpr successor]);
	} else {
		if (!assignmentList) assignmentList = [List new];
		[assignmentList add:newReceiver];
		[self successor:anExpr];
	}
	[temporaryVariablePool add:newReceiver];
	return self;
}
- free { [assignmentList free]; [value free]; return [super free]; }
\Rogue\Monster\
else
  echo "will not over write ./src/Expr.m"
fi
if `test ! -s ./src/FunctionTranslation.m`
then
echo "writting ./src/FunctionTranslation.m"
cat > ./src/FunctionTranslation.m << '\Rogue\Monster\'
#include "Producer.h"
= FunctionTranslation : AbstractTranslation CATEGORIES() {
	id functionName;
	id functionArgumentList;
}
+ name:aFunctionName args:anArgumentList {
	self = [super new];
	functionName = aFunctionName;
	functionArgumentList = anArgumentList;
	return self;
}
- genReceiver:aReceiver selector:aSelector {
	id arg; unsigned argNumber = 0; USE Msg;
	[functionName gen]; gc('(');
	for (arg = functionArgumentList; arg; arg = [arg successor]) {
		STR name = [arg str]; 
		if (argNumber != 0) gc(',');
		if (*name == '%') {
			unsigned index = atoi(name+1);
			if (index == 0) [aReceiver gen];
			else if (index >= [aSelector size])
				wer("argument offset %d out of range", index);
			else [[[aSelector at:index-1] argument] gen];
		} else if (argNumber == 0) [aReceiver gen];
		else [[[aSelector at:argNumber-1] argument] gen];
		argNumber++;
	}
	gc(')'); return self;
}
- (STR)str { return [functionName str]; }
#define MAXARRAY 2048
- asTypedByteArray { char buf[MAXARRAY]; id arg; USE ByteArray;
	strcpy(buf, [functionName str]);
	for (arg = functionArgumentList; arg; arg = [arg successor]) {
		sprintf(buf+strlen(buf), "(%s)%s ", 
			[[arg argumentType] str], [[arg argumentName] str]);;
	}
	return [ByteArray str:buf];
}
\Rogue\Monster\
else
  echo "will not over write ./src/FunctionTranslation.m"
fi
if `test ! -s ./src/Identifier.m`
then
echo "writting ./src/Identifier.m"
cat > ./src/Identifier.m << '\Rogue\Monster\'
#include "Producer.h"
	USE Set, OrdCltn;
	IMPORT id identifierTranslator;
= Identifier:ByteArray CATEGORIES() 
	{ id translation, type; }
+ name:aByteArray 
	{ return [self str:[aByteArray str]]; }
+ str:(STR)aString { 
	self = [super str:aString];
	type = types.UNKNOWN;
	translation = [identifierTranslator find:self];
	return self;
}
+ uniqueIdentifier:(STR)aString { static int uniqueness = 0;
	return [self sprintf:"%s%d", aString, uniqueness++];
}
- gen {
	if (translation) [translation gen];
	else gs([self str]); 
	return self; 
}
- genDeclaration {
	if (translation) [translation genDeclaration];
	else {
		if (type == nil) gs("<nil>"); else [type gen];
		gc(' '); gs([self str]); gc(';');
	}
	return self;
}
- type { 
	if (translation) return type = [translation type];
	// dbg("%s: (%s)%s\n", NAMEOF(self), [type str], [self str]);
	// if (type == types.UNKNOWN) [self type:types.ID rule:"default: first use"];
	return type; 
}
- type:aType rule:(STR)aString {
	if (translation && type != aType) {
		info("attempt to change type of translated symbol %s ignored (%s)",
			[self str], aString);
		return self;
	}
	if (aType == nil)
		return [self error:"nil type"]; 
	if (type != types.UNKNOWN && aType != type) {
		wer("%s %s; tried to change type from %s to %s ignored (%s)",
			NAMEOF(self), [self str], [type str], [aType str], aString);
	} else {
		info("type of %s is (%s) (%s)\n", [self str], [aType str], aString);
		type = aType;
	}
	return self;
}
- free { return nil; }
=:
\Rogue\Monster\
else
  echo "will not over write ./src/Identifier.m"
fi
if `test ! -s ./src/IdentifierTranslation.m`
then
echo "writting ./src/IdentifierTranslation.m"
cat > ./src/IdentifierTranslation.m << '\Rogue\Monster\'
// type inferencing template
#include "Producer.h"
#include "assert.h"
	USE Set, IntArray, Msg;
	IMPORT id identifierTranslator, globalSymbols;
= IdentifierTranslation:ByteArray CATEGORIES() 
	{ id type, targetIdentifier; }
+ sourceName:sourceIdentifier targetType:aType targetName:anIdentifier {
	id result;
	self = [super str:[sourceIdentifier str]]; [sourceIdentifier free];
	targetIdentifier = anIdentifier;
	if (aType == 0 || aType == types.UNKNOWN) type = types.ID;
	else type = aType;
	[targetIdentifier type:type rule:"explicit rule"];
#ifndef COXLIB
	if ([identifierTranslator addNTest:self]) result = self;
	else result = [identifierTranslator find:self];
#else
	result = [identifierTranslator add:self];
#endif
	if (result && result != self && result->type != type) {
		dbg("result=%x result->type=%x\n", result, result->type);
		wer("incompatible translations for identifier %s. Using %s, ignoring %s",
			[self str], [type str], [result->type str]);
	}
	[globalSymbols add:self];
	return self;
}
- type
	{ return type; }
- type:aType rule:(STR)aString { 
	info("IdentifierTranslation %s ignored type change from %s to %s",
		[self str], [type str], [aType str]);
	return self; 
}
- gen 
	{ gs([targetIdentifier str]); return self; }
- genDeclaration { 
	[type gen]; gc(' '); gs([targetIdentifier str]); gc(';');
	return self;
}
- targetIdentifier
	{ return targetIdentifier; }
- free
	{ return nil; }
- asTypedByteArray 
	{ return [ByteArray sprintf:"(%s)%s", [type str], [self str]]; }
=:
\Rogue\Monster\
else
  echo "will not over write ./src/IdentifierTranslation.m"
fi
if `test ! -s ./src/List.m`
then
echo "writting ./src/List.m"
cat > ./src/List.m << '\Rogue\Monster\'
#include "Producer.h"
= List:OrdCltn CATEGORIES()
#ifndef COXLIB
- gen { [self elementsPerform:_cmd]; return self; }
#else
- gen { [self eachElementPerform:_cmd]; return self; }
#endif
\Rogue\Monster\
else
  echo "will not over write ./src/List.m"
fi
if `test ! -s ./src/METHODDECLS.m`
then
echo "writting ./src/METHODDECLS.m"
cat > ./src/METHODDECLS.m << '\Rogue\Monster\'
#include "Producer.h"
= METHODDECLS:Object CATEGORIES() {}
- (BOOL)isEmpty {;}
- (BOOL)isEqual:aStr {;}
- (BOOL)isEqualSTR:(STR)aStr {;}
- (BOOL)isUnary {;}
- (STR)str {;}
- (unsigned)hash {;}
- (unsigned)size {;}
- add:aLink {;}
- argument {;}
- argument:anArgument {;}
- argumentType {;}
- array:anArray {;}
- asByteArray {;}
- assign:aList {;}
- assign:anAssignmentList value:aValue {;}
- at:(unsigned)anInt {;}
- cascade:anExpr {;}
- category:aString {;}
- classVariableNames:aString {;}
- comment:aString {;}
- elementsPerform:(SEL)aSelector with:arg1 with:arg2 {;}
- elementsPerform:(SEL)aSelector with:arg1 {;}
- elementsPerform:(SEL)aSelector {;}
- eachElementPerform:(SEL)aSelector with:arg1 with:arg2 {;}
- eachElementPerform:(SEL)aSelector with:arg1 {;}
- eachElementPerform:(SEL)aSelector {;}
- expr {;}
- expr:anExpr {;}
- free {;}
- freeContents {;}
- gen {;}
- genDeclaration {;}
- genExpr {;}
- genPrivate {;}
- genReceiver:aReceiver selector:aSelector {;}
- initialize {;}
- insert:aLink {;}
- install:aTemplate translation:aTranslation {;}
- instanceVariableNames:aString {;}
- lastElement {;}
- name:aByteArray {;}
- name:aFunctionName args:anArgumentList {;}
- name:aString argument:anArgument {;}
- poolDictionaries:aString {;}
- predecessorOf:aLink {;}
- primitive:aToken {;}
- receiver {;}
- receiver:anObject selector:aSelector {;}
- receiver:anObject {;}
- receiverType {;}
- receiverType:aType selector:aSelector {;}
- remove:aLink {;}
- selector {;}
- selector:aSelector asFactory:(BOOL)isFactoryMethod {;}
- selector:aSelector {;}
- sourceName:sourceIdentifier targetType:aType targetName:anIdentifier {;}
- statements:aStatementList {;}
- str:(STR)aString {;}
- successor {;}
- successor:aLink {;}
- superclass:aClass {;}
- template:aTemplate translation:aTranslation {;}
- translation {;}
- translation:aTranslation {;}
- translationFor:aMsg {;}
- type {;}
- type:aType name:aName {;}
- type:aType rule:(STR)aString {;}
- type:aType translation:aByteArray {;}
- type:aType {;}
- uniqueIdentifier:(STR)aString {;}
- value {;}
- value:aValue {;}
- variables:aVarList {;}
\Rogue\Monster\
else
  echo "will not over write ./src/METHODDECLS.m"
fi
if `test ! -s ./src/Method.m`
then
echo "writting ./src/Method.m"
cat > ./src/Method.m << '\Rogue\Monster\'
#include "Producer.h"
	IMPORT id symbolScope;
	USE Set, Identifier;
	EXPORT id temporaryVariablePool = nil;
= Method:Object CATEGORIES() {
	id selector, comment, primitive, statements; 
	id argumentVariables, localVariables;
	id type, concatenatedSelector;
	BOOL isFactory; 
	id translation;
}
+ selector:aSelector asFactory:(BOOL)aBoolean { id sel, arg;
	self = [super new]; selector = aSelector; isFactory = aBoolean;
	concatenatedSelector = [aSelector asByteArray];
	argumentVariables = [Set new]; type = types.UNKNOWN;
	[argumentVariables add:[[Identifier str:"self"] 
		type:types.ID rule:"hardwired"]];
	for (sel = aSelector; sel && (arg = [sel argument]); sel = [sel successor])
		[argumentVariables add:arg];
	[symbolScope add:argumentVariables];
	temporaryVariablePool = localVariables = [Set new];
	return self;
}
- receiverType
	{ return types.ID; }
- comment:aString { comment = aString; return self; }
- variables:aVarList { 
	[aVarList addContentsTo:localVariables];
	[symbolScope add:localVariables];
	return self;
}
- selector
	{ return selector; }
- statements:aStmtList 
	{ statements = aStmtList; return self; }
- primitive:aToken 
	{ primitive = aToken; return self; }
- gen { USE Return;
dbg("//=======================Method gen==================================\n");
	[self type];	// this triggers the type inferencing machinery
dbg("//-----------------------Method gen----------------------------------\n");
	gn(); gc(isFactory ? '+' : '-'); gc(' ');
	if (type != types.ID) { gc('('); [type gen]; gc(')'); }
	[selector genDeclaration]; gs(" {");
#ifndef COXLIB
	[localVariables elementsPerform:@selector(genDeclaration)];
#else
	[localVariables eachElementPerform:@selector(genDeclaration)];
#endif
	[primitive gen]; [statements gen]; 
	if (![[statements lastElement] isKindOf:Return]) gs("return self;");
	gc('}'); return self;
}
- type { IMPORT id msgTranslator; id t; STR failReason = "name not found";
	id key, sourceStr, msgTranslation, stmt, s; 
	if (translation) return [translation type];
	[statements type]; [selector type];
	key = [selector asByteArray]; sourceStr = [selector asTypedByteArray];
	if (msgTranslation = [msgTranslator find:key]) { unsigned i, n; 
		dbg("translation for method %s\n", [sourceStr str]);
		if (![selector isUnary]) { id s;
			for (s = selector; s; s = [s successor]) { id st = [s type];
				if (st == types.UNKNOWN) [s type:types.ID rule:"method arg"];
			}
		}
		for (n = [msgTranslation size], i = 0; i < n; i++) { 
			id s, p, targetPattern = [msgTranslation at:i], targetStr;
			failReason = "types didn't match";
			if (![selector isUnary]) { unsigned offset = 1;
				for (s = selector; s; s = [s successor]) {
					id rt = [s type], pt = [targetPattern at:offset++];
					dbg("	actualArgType=%s patternArgType=%s\n",
						[rt str], [pt str]);
					if ((pt != types.ANY) && (rt != pt))
						goto tryAgain;	// break out to try next pattern
				}
			}
			translation = [targetPattern translation];
			type = [translation type];
			targetStr = [translation asTypedByteArray];
			info("method %s translated to (%s)%s (type match)\n", 
				[sourceStr str], [type str], [targetStr str]);
			[targetStr free];
			[translation assignTypesTo:selector];
			goto succeed;
tryAgain:;
		}
	}
	info("method %s translated literally (%s)\n",
		[sourceStr str], failReason);
succeed:
	if (!type) {
		for (stmt = statements; stmt; stmt = [stmt successor]) {
			if ([stmt isKindOf:Return])
				[self type:[stmt type] rule:"used type from return stmt"];
		}
	}
	if (type == types.UNKNOWN) [self type:types.ID rule:"default method type"];
	[key free]; [sourceStr free];
	return type;
}
- type:aType rule:(STR)aString {
	if (aType == nil) return [self error:"nil type"]; 
	if (type != types.UNKNOWN && aType != type) {
		wer("attempt to change type of method %s from %s to %s ignored (%s)",
			[self str], [type str], [aType str], aString);
	} else { id s = [selector asByteArray];
		info("type of method %s set to (%s) (%s)\n", 
			[s str], [aType str], aString);
		[s free]; type = aType;
	}
	return self;
}
- free { 
	[symbolScope remove:argumentVariables];
	[symbolScope remove:localVariables];
	[primitive free]; [selector free]; [comment free];
	[argumentVariables freeContents]; [argumentVariables free];
	[localVariables freeContents]; [localVariables free];
	[concatenatedSelector free];
	[statements free]; return [super free]; 
}
=:
\Rogue\Monster\
else
  echo "will not over write ./src/Method.m"
fi
if `test ! -s ./src/Msg.m`
then
echo "writting ./src/Msg.m"
cat > ./src/Msg.m << '\Rogue\Monster\'
#include "Producer.h"
= Msg:Object CATEGORIES() {
	id receiver;
	id selector;
	id translation;
}
	IMPORT id msgTranslator;
	USE Template;
+ receiver:anObject 
	{ return [[self new] receiver:anObject]; }
+ receiver:anObject selector:aSelector
	{ return [[[self new] receiver:anObject] selector:aSelector]; }
+ selector:aSelector
	{ return [[self new] selector:aSelector]; }
- receiver 
	{ return receiver; }
- receiverType
	{ return [receiver type]; }
- receiver:anObject 
	{ receiver = anObject; return self; }
- selector 
	{ return selector; }
- selector:aSelector { 
	selector = aSelector;
	return self; 
}
- free {
	[receiver free];
	[selector free];
	return [super free]; 
}

// ByteArray Emulation
- (STR)str 
	{ return [selector str]; }
- (unsigned)hash 
	{ return _strhash([self str]); }
- (BOOL)isEqual:aStr	
	{ return strcmp([self str], [aStr str]) == 0; }
- (BOOL)isEqualSTR:(STR)aStr 
	{ return strcmp([self str], aStr) == 0; }
- type { id type;
	if (!translation) { unsigned i, n; STR failReason = 0;
		id s, key = [selector asByteArray];
		id msgTranslation, receiverType = [receiver type];
		id sourceStr = [selector asTypedByteArray];
		dbg("translating message [(%s) %s]\n",
			[[receiver type] str], [sourceStr str]);
		if (![selector isUnary]) {
			for (s = selector; s; s = [s successor]) {
				id st = [s argumentType];
				if (st == types.UNKNOWN) [s type:types.ID rule:"msg arg"];
			}
		}
		if (msgTranslation = [msgTranslator find:key]) {
			for (n = [msgTranslation size], i = 0; i < n; i++) {
				unsigned offset = 0; id s, targetStr;
				id targetPattern = [msgTranslation at:i];
				id patternReceiverType = [targetPattern at:offset++];
				dbg("	actualReceiverType=%s patternReceiver=%s\n",
				[receiverType str], [patternReceiverType str]);
				failReason = "receiver types didn't match";
				if (patternReceiverType == types.ANY 
					|| patternReceiverType == receiverType) {
					if (![selector isUnary]) { // if not unary selector
						failReason = "argument types didn't match";
						for (s = selector; s; s = [s successor]) {
							id rt = [s type], pt = [targetPattern at:offset++];
							dbg("	actualArgType=%s patternArgType=%s\n",
								[rt str], [pt str]);
							if ((pt != types.ANY) && (rt != pt))
								goto fail;	// break out to try next pattern
						}
					}
					translation = [targetPattern translation];
					targetStr = [translation asTypedByteArray];
					info("message [(%s)%s] translated to (%s)%s (type match)\n",
						[receiverType str], [sourceStr str],
						[[translation type] str], [targetStr str]);
					[targetStr free];
					goto succeed;
				}
fail:;
			}
		} else failReason = "name not found";
		info("message [(%s)%s] translated literally (%s)\n", 
			[receiverType str], [sourceStr str], failReason);
succeed:
		[key free]; [sourceStr free]; 
		if ([receiver type] == types.UNKNOWN)
			[receiver type:types.ID rule:"message receiver"];
	}
	type = translation ? [translation type] : types.ID;
	return type == types.UNKNOWN ? types.ID : type;
}
- gen {
	if (translation) [translation genReceiver:receiver selector:selector];
	else { 
		gc('['); [receiver gen]; gc(' '); [selector gen]; gc(']'); }
	return self; 
}
=:
\Rogue\Monster\
else
  echo "will not over write ./src/Msg.m"
fi
if `test ! -s ./src/MsgArgPattern.m`
then
echo "writting ./src/MsgArgPattern.m"
cat > ./src/MsgArgPattern.m << '\Rogue\Monster\'
#include "Producer.h"
= MsgArgPattern : IdArray CATEGORIES() 
	{ id translation; }
+ template:aTemplate translation:aTranslation { id s; unsigned i = 0;
	self = [self new:[aTemplate size]+1];
	[self at:i++ put:[aTemplate receiverType]];
	for (s = [aTemplate selector]; s; s = [s successor]) {
		id t = [s type];
		if (t == 0 || t == types.UNKNOWN) t = types.ANY;
		[self at:i++ put:t];
	}
	return [self translation:aTranslation];
}
- type
	{ return [translation type]; }
- translation:aTranslation
	{ translation = aTranslation; return self; }
- translation
	{ return translation; }
\Rogue\Monster\
else
  echo "will not over write ./src/MsgArgPattern.m"
fi
if `test ! -s ./src/MsgNamePattern.m`
then
echo "writting ./src/MsgNamePattern.m"
cat > ./src/MsgNamePattern.m << '\Rogue\Monster\'
// Each message may have several translations depending on the type of
//	the receiver and the message's arguments. MsgNamePattern holds the
//	name of the message (concatenated selector in selectorByteArray)
//	and an ordered collection of MsgArgPatterns. These are IdArrays
//	holding the type of the receiver followed by the types of the arguments.
//	Each MsgArgPattern also holds the translation for the messages that
//	match in name and argument type.
#include "Producer.h"
= MsgNamePattern : OrdCltn CATEGORIES()
	{ id selectorByteArray; }
+ name:aByteArray
	{ self = [super new]; selectorByteArray = aByteArray; return self; }
- (unsigned)hash
	{ return [selectorByteArray hash]; }
- (BOOL)isEqual:aMsgNamePattern
	{ return [selectorByteArray isEqual:aMsgNamePattern]; }
- (STR)str
	{ return [selectorByteArray str]; }
\Rogue\Monster\
else
  echo "will not over write ./src/MsgNamePattern.m"
fi
if `test ! -s ./src/MsgTranslation.m`
then
echo "writting ./src/MsgTranslation.m"
cat > ./src/MsgTranslation.m << '\Rogue\Monster\'
#include "Producer.h"
= MsgTranslation : AbstractTranslation CATEGORIES()
	{ id receiverType, selector; }
+ receiverType:aType selector:aSelector {
	self = [super type:types.ID];
	receiverType = aType ? aType : types.ANY;
	selector = aSelector;
	return self;
}
- selector
	{ return selector; }
- receiverType
	{ return receiverType; }
- (STR)str
	{ return [selector str]; }
- genReceiver:aReceiver selector:aSelector {
	USE Msg; unsigned argNumber = 0; id sel;
	gc('['); [aReceiver gen]; 
	for (sel = selector; sel; sel = [sel successor], argNumber++) {
		STR name = [sel str]; gc(' ');
		if (*name == '%') {
			unsigned index = atoi(&name[1]);
			if (index == 0)
				wer("%%0 not allowed in MsgPattern rules");
			else if (index >= [aSelector size]) {
				wer("argument offset %d out of range", index);
			} else {
				gs([[selector at:index-1] str]);
				[[[aSelector at:index-1] argument] gen];
			}
		} else { 
			gs([[selector at:argNumber] str]); 
			[[[aSelector at:argNumber] argument] gen];
		}
	}
	gc(']'); return self;
}
- asTypedByteArray 
	{ return [selector asTypedByteArray]; }
- free
	{ return nil; }
- assignTypesTo:aSelector {
	id s = aSelector, p = [self selector];
	while(s && p) { [s type:[p type]];
		s = [s successor]; p = [p successor];
	}
	return self;
}
\Rogue\Monster\
else
  echo "will not over write ./src/MsgTranslation.m"
fi
if `test ! -s ./src/MsgTranslator.m`
then
echo "writting ./src/MsgTranslator.m"
cat > ./src/MsgTranslator.m << '\Rogue\Monster\'
// MsgTranslator: a set of MsgNamePatterns. These hold a string (the
//	concatenated selector characters) and a collection of MsgArgPatterns
//	describing one of the types (for receiver and arguments) for which
//	a translation is known
#include "Producer.h"
	EXPORT id msgTranslator = nil;
	USE MsgNamePattern, MsgArgPattern, Msg;
= MsgTranslator : Set CATEGORIES()
+ initialize 
	{ if (!msgTranslator) msgTranslator = [self new]; return self; }
- install:aTemplate translation:aTranslation {
	id name = [[aTemplate selector] asByteArray];
	id msgNamePattern = [self find:name];
	if (msgNamePattern) [name free];
	else [self add:msgNamePattern=[MsgNamePattern name:name]];
	[msgNamePattern add:[MsgArgPattern
		template:aTemplate translation:aTranslation]];
	return self;
}
\Rogue\Monster\
else
  echo "will not over write ./src/MsgTranslator.m"
fi
if `test ! -s ./src/Node.m`
then
echo "writting ./src/Node.m"
cat > ./src/Node.m << '\Rogue\Monster\'
#include "Producer.h"
= Node:Object CATEGORIES() { id successor; }
- successor { return successor; }
- successor:aLink { id me = successor; successor = aLink; return me; }

- lastElement { while(successor) self = successor; return self; }
// Reply the predecessor of the indicated link.
- predecessorOf:aLink {
	do { if (successor == aLink) return self; } while (self = successor);
	return nil;
}
// Reply the n'th link in this chain.
- at:(unsigned)anInt { register unsigned i = anInt; register id obj = self;
	while (i-- && obj) obj = obj->successor;
	return obj ? obj : [self error:"range error: %d", anInt];
}
// Append another instance to this chain.
- add:aLink { id me = self; while (successor) self = successor;
	successor = aLink; return me;
}
// Free this link and all successors
- freeContents { register id next;
	do { next = successor; [super free]; } while (self = next);
}
// remove
- remove:aLink { self =[self predecessorOf:aLink];
	 if (self == nil) return nil;
	 successor= [ aLink successor];
	 return aLink;
}
// insert
- insert:aLink 
	{ [ aLink successor:successor]; successor= aLink; return self; }

- gen 
	{ [self show]; [successor show]; return self; }
- free 
	{ [successor free]; return [super free]; }

// Reply the number of linked instances
#ifdef OBSOLETE
- (unsigned)size 
	{ register unsigned n = 1; while(self = successor) n++; return n; }
#endif
- (unsigned)size 
	{ unsigned i; for (i=1; self = successor; i++); return i; }

#ifndef COXLIB
- elementsPerform:(SEL)aSelector {
	do { [self perform:aSelector]; } while (self = successor);
	return self;
}
- elementsPerform:(SEL)aSelector with:arg1 {
	do { [self perform:aSelector with:arg1]; } while (self = successor);
	return self;
}
- elementsPerform:(SEL)aSelector with:arg1 with:arg2 {
	do { [self perform:aSelector with:arg1 with:arg2]; } while (self = successor);
	return self;
}
#else
- eachElementPerform:(SEL)aSelector {
	do { [self perform:aSelector]; } while (self = successor);
	return self;
}
- eachElementPerform:(SEL)aSelector with:arg1 {
	do { [self perform:aSelector with:arg1]; } while (self = successor);
	return self;
}
- eachElementPerform:(SEL)aSelector with:arg1 with:arg2 {
	do { [self perform:aSelector with:arg1 with:arg2]; } while (self = successor);
	return self;
}
#endif
=:
\Rogue\Monster\
else
  echo "will not over write ./src/Node.m"
fi
if `test ! -s ./src/Scope.m`
then
echo "writting ./src/Scope.m"
cat > ./src/Scope.m << '\Rogue\Monster\'
// Symbol scoping
//	A scope is an ordered collection Sets of identifiers
#include "Producer.h"
	USE Set, IntArray, Msg;
	EXPORT id symbolScope  = nil,
		undefinedSymbols = nil,
		globalSymbols = nil,
		identifierTranslator = nil;
= Scope:OrderedCollection CATEGORIES() 
+ initialize { 
	if (!symbolScope) {
		symbolScope = [self new]; 
		undefinedSymbols = [Set new];
		globalSymbols = [Set new];
		[symbolScope add:globalSymbols];
		[symbolScope add:undefinedSymbols];
		identifierTranslator = [Set new];
	}
	return self;
}
=:
id findSymbol(aVariable) id aVariable; {
	int i, n = [symbolScope size];
	for (i = n-1; i >= 0; i--) { id hit;
		if (hit = [[symbolScope at:i] find:aVariable]) 
			return hit;
	}
	info("undefined %s %s\n", NAMEOF(aVariable), [aVariable str]);
	[undefinedSymbols add:aVariable]; return aVariable;
}
\Rogue\Monster\
else
  echo "will not over write ./src/Scope.m"
fi
if `test ! -s ./src/NumberConstant.m`
then
echo "writting ./src/NumberConstant.m"
cat > ./src/NumberConstant.m << '\Rogue\Monster\'
#include "Producer.h"
= NumberConstant : Constant CATEGORIES() {}
- gen 
	{ gs([self str]); return self; }
+ str:(STR)aString
	{ return [super str:aString]; }
- type 
	{ return index([self str], '.') ? types.FLOAT : types.INT; }
\Rogue\Monster\
else
  echo "will not over write ./src/NumberConstant.m"
fi
if `test ! -s ./src/Return.m`
then
echo "writting ./src/Return.m"
cat > ./src/Return.m << '\Rogue\Monster\'
#include "Producer.h"
= Return:Node CATEGORIES() { id body; }
+ expr:anExpr { self = [super new]; body = anExpr; return self; }
- gen { [self genExpr]; gc(';'); return self; }
- genExpr { gs("return "); [body gen]; return self; }
- free { [body free]; return [super free]; }
- type { return [body type]; }
\Rogue\Monster\
else
  echo "will not over write ./src/Return.m"
fi
if `test ! -s ./src/Selector.m`
then
echo "writting ./src/Selector.m"
cat > ./src/Selector.m << '\Rogue\Monster\'
#include "Producer.h"
#define strEq(p, q) (strcmp(p, q) == 0)
#define strHas(s, c) (index(s, c) != 0)
#define MAXSELECTOR 512
	STR strCopy(), xlate();
	USE ByteArray, IdArray; 

= Selector:Node CATEGORIES() 
	{ STR name; id argument; }
+ name:aString argument:anArgument 
	{ return [[self name:aString] argument:anArgument]; }
+ name:aString 
	{ return [self str:[aString str]]; }
+ str:(STR)aString { 
	self = [super new];
	name = strCopy(aString);
	if (strlen(name) < 1) return [self error:"nil selector"];
	return self; 
}
// Inherited deepCopy seems to not copy the name argument correctly
- deepCopy {
	id t = [[isa str:name] argument:argument]; 
	[t successor:[successor deepCopy]];
	return t;
}
- (BOOL)isUnary
	{ return argument == nil; }
- asByteArray { char strBuf[MAXSELECTOR]; strBuf[0] = 0;
	do { strcat(strBuf, name); } while (self = successor);
	return [ByteArray str:strBuf];
}
- asTypeArray { id typeArray;
	if ([self isUnary]) typeArray = [IdArray new:0];
	else { 
		typeArray = [IdArray new:[self size]];
		do { [typeArray add:[argument type]]; } while (self = successor);
	}
	return typeArray;
}
- asTypedByteArray { char strBuf[MAXSELECTOR]; strBuf[0] = 0;
	do { strcat(strBuf, name);
		if (argument)
			sprintf(strBuf+strlen(strBuf), "(%s) ", [[argument type] str]);;
	} while (self = successor);
	return [ByteArray str:strBuf];
}

// ByteArray emulation
- (STR)str 
	{ return name; }
- (unsigned)hash 
	{ return _strhash(name); }
- (BOOL)isEqual:anObject 
	{ return self == anObject || strcmp(name, [anObject str]) == 0; }
- (BOOL)isEqualSTR:(STR)aStr 
	{ return strcmp(name, aStr) == 0; }
- type {
	if (successor) [successor type];
	return [argument type];
}
- type:aType
	{ return [self type:aType rule:"force"]; }
- type:aType rule:(STR)aString 
	{ [argument type:aType rule:aString]; return self; }
- argument:anArgument 
	{ argument = anArgument; return self; }
- argument 
	{ return argument; }
- argumentType
	{ return [argument type]; }
- free 
	{ free(name); [argument free]; return [super free]; }
- gen {
	gs(xlate(name)); [argument gen]; 
	if (successor) { gc(' '); [successor gen]; }
	return self; 
}
- genDeclaration {
	gs(xlate(name));
	if (argument && [argument type] != types.ID) 
		{ gc('('); gs([[argument type] str]); gc(')'); }
	[argument gen];
	if (successor) { gc(' '); [successor genDeclaration]; }
	return self; 
}
=:
// Translate Smalltalk binary selectors to Objective-C keyword
static STR xlate(s) STR s; {
	static STR binarySelectorTbl= // parallel arrays!
			"+-/\\*~<>=@%&?!,|",
		objcSelectorStrings[]= { "plus", "minus", "slash", "backslash",
			"times", "tilde", "lesser", "greater", "equals", "point", "percent",
			"ampersand", "question", "bang", "comma", "or", "/*@*/", 0};
	STR i, index(); static char buf[MAXSELECTOR];
	*buf = 0;
	if (i = index(binarySelectorTbl, s[0])) {
		strcat(buf, objcSelectorStrings[i-binarySelectorTbl]);
		if (s[1]) {
			if (i = index(binarySelectorTbl, s[1]))
				strcat(buf, objcSelectorStrings[i-binarySelectorTbl]);
			else wer("bad char in binary selector <%c>", s[1]);
			if (s[2]) wer("binary selector more than 2 chars long <%s>", s);
		}
		strcat(buf, ":");
		return buf;
	}
	return s;
}
\Rogue\Monster\
else
  echo "will not over write ./src/Selector.m"
fi
if `test ! -s ./src/SelectorConstant.m`
then
echo "writting ./src/SelectorConstant.m"
cat > ./src/SelectorConstant.m << '\Rogue\Monster\'
#include "Producer.h"
= SelectorConstant : Constant CATEGORIES() {}
- type
	{ return types.SELECTOR; }
- gen
	{ id t = types.SELECTOR;  
	dbg("%s: (%s)%s\n", NAMEOF(self), [t str], [self str]);
	gs("@selector("); [super gen]; gc(')'); return self; }
=:
\Rogue\Monster\
else
  echo "will not over write ./src/SelectorConstant.m"
fi
if `test ! -s ./src/StArray.m`
then
echo "writting ./src/StArray.m"
cat > ./src/StArray.m << '\Rogue\Monster\'
#include "Producer.h"
= StArray:OrdCltn  CATEGORIES() 
	{ id type; }
- gen { id s, m;
	gs("={"); 
	for (s = [self eachElement]; m = [s next]; )
		{ [m gen]; gs(", "); }
	[s free]; gc('}'); return self; 
}
- type { id s, m;
	if (type) return type;
	if ([self isEmpty]) return types.ID;
	type = [[self firstElement] type];
	for (s = [self eachElement]; m = [s next]; )
		if ([m type] != type) wer("this array holds diverse types");
	[s free];
	return type;
}
\Rogue\Monster\
else
  echo "will not over write ./src/StArray.m"
fi
if `test ! -s ./src/Stmt.m`
then
echo "writting ./src/Stmt.m"
cat > ./src/Stmt.m << '\Rogue\Monster\'
#include "Producer.h"
= Stmt:Node CATEGORIES() { id expr, type; }
+ expr:anExpr { self = [super new]; expr = anExpr; return self; }
- expr { return expr; }
- free { [expr free]; return [super free]; }
- gen {
	[expr gen]; if (type != types.STMT) gc(';'); 
	[successor gen]; return self; 
}
- genExpr { [expr gen];
	if (successor) { if (type != types.STMT) gc(';'); [successor gen]; }
	return self; 
}
- type { 
	if (type) return type;
	type = [expr type]; 
	[successor type];
	return type;
}
\Rogue\Monster\
else
  echo "will not over write ./src/Stmt.m"
fi
if `test ! -s ./src/StringConstant.m`
then
echo "writting ./src/StringConstant.m"
cat > ./src/StringConstant.m << '\Rogue\Monster\'
#include "Producer.h"
= StringConstant : Constant CATEGORIES() {}
+ str:(STR)aString { STR rindex(), p;
	if (*aString == '\'' && (p = rindex(aString, '\''))) {
		char c = *p; *p = 0;
		self = [super str:aString+1];
		*p = c;
		return self;
	} else return [super str:aString];
}
- type 
	{ id t = types.CSTRING; return t; }
- gen
	{ gc('"'); [super gen]; gc('"'); return self; }
=:
\Rogue\Monster\
else
  echo "will not over write ./src/StringConstant.m"
fi
if `test ! -s ./src/StringTranslation.m`
then
echo "writting ./src/StringTranslation.m"
cat > ./src/StringTranslation.m << '\Rogue\Monster\'
// Translate message to string
#include "Producer.h"
#include "ctype.h"
= StringTranslation:AbstractTranslation  CATEGORIES() 
	{ id translation; }
+ type:aType translation:aByteArray 
	{ return [[self type:aType] translation:aByteArray]; }
- translation:aByteArray
	{ translation = aByteArray; return self; }
- (STR)str
	{ return [translation str]; }
- genReceiver:aReceiver selector:aSelector {
	STR rindex(), q, p;
	p = [translation str];
	for (; *p; p++) {
		if (*p == '\\') {
			gc(*p++); gc(*p); continue;
		} else if (*p == '%') {
			unsigned index = atoi(++p);
			if (index == 0) [aReceiver gen];
			else if (--index >= [aSelector size])
				wer("bad rule", index+1);
			else [[[aSelector at:index] argument] gen];
			while (isdigit(*p)) p++; p--;
		} else if (*p == '\n') {
			while(isspace(*p)) p++; p--;
		} else gc(*p);
	}
	return self;
}
- asTypedByteArray 
	{ return [translation asByteArray]; }
=:
static verifyArgCount(targetString, sourcePattern)
	STR targetString; id sourcePattern; 
{
	STR p;
	for (p = targetString; *p; p++) {
		if (*p == '\\') {
			*p++; continue;
		} else if (*p == '%') {
			unsigned index = atoi(++p);
			if (index != 0 && --index >= [sourcePattern size])
				wer("no such argument");
			while (isdigit(*p)) p++; p--;
		}
	}
}
\Rogue\Monster\
else
  echo "will not over write ./src/StringTranslation.m"
fi
if `test ! -s ./src/Template.m`
then
echo "writting ./src/Template.m"
cat > ./src/Template.m << '\Rogue\Monster\'
#include "Producer.h"
#define MAXSELECTOR 5000
= Template : ByteArray CATEGORIES() 
	{ id receiverType, selector; }
+ receiverType:aType selector:aSelector {
	char strBuf[MAXSELECTOR];
	id s = aSelector; strBuf[0] = 0;
	for (s = aSelector; s;  s = [s successor]) strcat(strBuf, [s str]);
	self = [super str:strBuf];
	receiverType = aType;
	selector = aSelector;
	return self;
}
- receiverType
	{ return receiverType; }
- selector
	{ return selector; }
\Rogue\Monster\
else
  echo "will not over write ./src/Template.m"
fi
echo "Finished archive 4 of 5"
exit
----
Dieter H. Zebbedies ('dee-ter  ayech  'zeb-ed-eez)
 Zebb-Hoff Mach. Tool's Automated Manufacturing Project Cleveland, OH
 (USnail): 9535 Clinton Rd, Cleveland, OH 44144 (+216 631 6100) (+216 741-5994)
 (UUCP): ...{decvax,sun,cbosgd}!cwruecmp!zhmti!dieter
 (CSNET/ARPA/BITNET): dieter@CWRU.EDU

dietz@zhmti.UUCP (Dieter H. Zebbedies) (08/20/87)

"Producer", A package to translate Smalltalk-80 code to your favorite
object oriented language, Objective-C.

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -d ./rules`
then
  mkdir ./rules
  echo "mkdir ./rules"
fi
if `test ! -s ./rules/generic.ru`
then
echo "writting ./rules/generic.ru"
cat > ./rules/generic.ru << '\Rogue\Monster\'
"ClassNames ==============================================================="
{ # ArrayedCollection (id) ArrayedCollection }
{ # Association (id) Assoc }
{ # Bag (id) Bag }
{ # Button (id) Button }
{ # ByteArray (id) ByteArray }
{ # Character (id) Character }
{ # Circle (id) Circle }
{ # Collection (id) Collection }
{ # Cursor (id) currentCursor }
{ # Dictionary (id) Dictionary }
{ # Display (id) currentDisplay }
{ # Drafting (id) Drafting }
{ # Form (id) Form }
{ # IdentityDictionary (id) IdentityDictionary }
{ # IdentitySet (id) IdentitySet }
{ # Interval (id) Interval }
{ # Line (id) Line }
{ # Link (id) Link }
{ # LinkedList (id) LinkedList }
{ # LookupKey (id) LookupKey }
{ # Magnitude (id) Magnitude }
{ # MappedCollection (id) MappedCollection }
{ # Object (id) Object }
{ # OrderedCollection (id) OrderedCollection }
{ # PositionableStream (id) PositionableStream }
{ # ReadStream (id) ReadStream }
{ # ReadWriteStream (id) ReadWriteStream }
{ # Rectangle (id) Rectangle }
{ # RunArray (id) RunArray }
{ # ScheduledControllers (id) ScheduledControllers }
{ # SequenceableCollection (id) SequenceableCollection }
{ # Set (id) Set }
{ # SortedCollection (id) SortedCollection }
{ # StandardSystemView (id) StdSysView }
{ # Stream (id) Stream }
{ # String (id) String }
{ # StringHolder (id) StringHolder }
{ # StringHolderView (id) StringHolderView }
{ # SwitchController (id) SwitchController }
{ # SwitchView (id) SwitchView }
{ # Symbol (id) Symbol }
{ # Text (id) Text }
{ # View (id) View }
{ # WriteStream (id) WriteStream }
{ # display (id) currentWindow }
{ # sensor (id) currentWindow }
{ # Sensor (id) currentWindow }

"Globals.rules ==============================================================="
{ # super (id) super }
{ # false (BOOL)NO }
{ # nil (id)nil }
{ # true (BOOL)YES }
{ # aPoint (PT) aPoint }
{ # len (int) len }
{ species # (id)'%0->isa'}
{ next:(int) # (id)[next:(int)%1] } 
{ next:(int) put:(id) # (id)[next:(int)%1 put:(id)%2] }
{ # (id)[copyFrom:(int)anInteger to:(int)readLimitInteger] }
{ # (id)[new:(int)anInteger] }
{ # (id)[at:(int)anInteger] }
{ # (id)[at:(int)anInteger put:anObject] }
{ # (int)[size] }

"Numbers.rules ==============================================================="
{ & (BLOCK) # (int)'%0 && %1' }
{ & (BOOL) # (int)'%0 && %1' }
{ eqv:(BOOL) # (int)'%0 == %1' }
{ not # (BLOCK)'!%0' }
{ xor:(BOOL) # (int)'%0 ^ %1' }
{ | (BOOL) # (int)'%0 | %1' }
{ and:(BLOCK) # (int)'%0 && %1' }
{ (int) < (int)	# (BOOL) '%0 < %1' }
{ (int) <= (int)	# (BOOL) '%0 <= %1' }
{ (int) = (int)	# (BOOL) '%0 == %1' }
{ (int) > (int)	# (BOOL) '%0 > %1' }
{ (int) >= (int)	# (BOOL) '%0 >= %1' }
{ (float) < (float)	# (BOOL) '%0 < %1' }
{ (float) <= (float)	# (BOOL) '%0 <= %1' }
{ (float) = (float)	# (BOOL) '%0 == %1' }
{ (float) > (float)	# (BOOL) '%0 > %1' }
{ (float) >= (float)	# (BOOL) '%0 >= %1' }
{ (int) < (float)	# (BOOL) '%0 < %1' }
{ (int) <= (float)	# (BOOL) '%0 <= %1' }
{ (int) = (float)	# (BOOL) '%0 == %1' }
{ (int) > (float)	# (BOOL) '%0 > %1' }
{ (int) >= (float)	# (BOOL) '%0 >= %1' }
{ (float) < (int)	# (BOOL) '%0 < %1' }
{ (float) <= (int)	# (BOOL) '%0 <= %1' }
{ (float) = (int)	# (BOOL) '%0 == %1' }
{ (float) > (int)	# (BOOL) '%0 > %1' }
{ (float) >= (int)	# (BOOL) '%0 >= %1' }
{ ifFalse:(BLOCK) # (int)'if (!%0) %1' }
{ ifFalse:(BLOCK) ifTrue:(BLOCK) # (int)'(!%0) ? %1 : %2' }
{ ifFalse:(BLOCK) ifTrue:(BLOCK) # (STMT)'if (!%0) %1 else %2' }
{ ifTrue:(BLOCK) # (STMT)'if (%0) %1' }
{ ifTrue:(BLOCK) ifFalse:(BLOCK) # (int)'(%0) ? %1 : %2' }
{ ifTrue:(BLOCK) ifFalse:(BLOCK) # (STMT)'if (%0) %1 else %2' }
{ or:(BLOCK) # (BOOL) '%0 | %1' }
{ (int)+ (int)	# (int) '%0 + %1' }
{ (int)- (int)	# (int) '%0 - %1' }
{ (int)* (int)	# (int) '(%0) * (%1)' }
{ (int)/ (int)	# (int) '(%0) / (%1)' }
{ (int)// (int)	# (int) '(%0) // (%1)' }
{ (int)abs	# (int) abs((int)%0) }
{ (int)negated	# (int) '-%0' }
{ (int)quo:(int)	# (int) quo(%0) }
{ (int)reciprocal	# (int) '1/(%0)' }
{ (int)rem:(int)	# (int) '%0 \% %1' }
{ (int)raisedTo:(float)	# (int) '(int)raiseToPower((float)(%0), (float)(%1))' }
{ (int)raisedToInteger:(int)	# (int) '(int)raiseToPowerInt((float)(%0), %1)' }
{ (int)raisedToInteger:(float)	# (int) '(int)raiseToPowerInt((float)(%0), %1)' }
{ (int)sin	# (int) '(int)sin((float)(%0))' }
{ (int)sqrt	# (int) '(int)sqrt((float)(%0))' }
{ (int)tan	# (int) '(int)tan((float)(%0))' }
{ (int)\\ (int)	# (int) '%0 \\ %1' }
{ (int)raisedTo:(int)	# (int) 'raiseToPower(%0, %1)' }
{ (int)raisedToInteger:(int)	# (int) 'raiseToPointInt(%0, %1)' }
{ (int)squared	# (int) '%0*%0' }
{ (int)even	# (int) '(%0 & 1) == 0' }
{ (int)negative	# (int) '-%0' }
{ (int)odd	# (int) '(%0 & 1) != 0' }
{ (int)positive	# (int) '%0 >= 0' }
{ (int)sign	# (int) '%0 < 0' }
{ (int)strictlyPositive	# (int) '%0 > 0' }
{ (int)rounded	# (int) '%0' }
{ (int)roundTo:(int)	# (int) roundTo((int)%0, (int)%1) }
{ (int)truncated	# (int) truncated((int)%0) }
{ (int)truncateTo:(int)	# (int) truncateTo(%0, %1) }
{ (int)coerce:(int)	# (int) coerce(%0, %1) }
{ (int)generality	# (int) generality(%0) }
{ (int)retry:(BLOCK) coercing:(int)	# (int) retryCoercing(%0, %1, %2) }
{ (int)@ (int)	# (PT) pt(%0, %1) }
{ (int)asInteger	# (int) '(int)%0' }
{ (int)asFloat	# (float) '(float)%0' }
{ (float)asFloat	# (float) '%0' }
{ (int)asPoint	# (PT) pt(%0, %0) }
{ (float)asPoint	# (PT) pt(%0, %0) }
{ (int)to:(int)	# (int) to(%0, %1) }
{ (int)to:(int) by:(int)	# (int) toBy(%0, %1, %2) }
{ (int)to:(int) by:(int) do:(BLOCK)	# (STMT) 'for (i = %0; i < %1; i+= %2) %3' }
{ (int)to:(int) do:(BLOCK)	# (STMT) 'for(i = %0; i < %1; i++) %2' }
{ (int)timesRepeat:(BLOCK) # (STMT) 'for(i = 0; i < %0; i++) %1' }
{ (float)timesRepeat:(BLOCK) # (STMT) 'for(i = 0; i < %0; i++) %1' }
{ do:(BLOCK)	# (id) 'for(s = [%0 eachElement]; m = [s next];) %1; [s free];' }
{ whileTrue:(BLOCK)	# 'while(%0) %1' }
{ whileFalse:(BLOCK)	# 'while(!%0) %1' }
{ (int)storeOn:(IOD)	# (int) storeOn(%0, %1) }
{ (int)readFrom:(IOD)	# (int) readFrom(%0, %1) }
{ (float)+ (float)	# (float) '%0 + %1' }
{ (float)- (float)	# (float) '%0 - %1' }
{ (float)* (float)	# (float) '(%0) * (%1)' }
{ (float)/ (float)	# (float) '(%0) / (%1)' }
{ (float)// (float)	# (float) '(%0) // (%1)' }
{ (float)abs	# (float) abs((float)%0) }
{ (float)negated	# (float) '-(%0)' }
{ (float)quo:(float)	# (float) 'quo(%0)' }
{ (float)reciprocal	# (float) '1./(%0)' }
{ (float)rem:(float)	# (float) '(%0) \% (%1)' }
{ (float)\\ (float)	# (float) '(%0) \\ (%1)' }
{ (float)arcCos	# (float) arcCos(%0) }
{ (float)arcSin	# (float) arcSin(%0) }
{ (float)arcTan	# (float) arcTan(%0) }
{ (float)cos	# (float) cos(%0) }
{ (int)cos	# (float) 'cos((float)(%0))' }
{ (float)exp	# (fint) exp(%0) }
{ (int)exp	# (float) 'exp((float)(%0))' }
{ (float)floorLog:(float)	# (float) floorLog(%0, %1) }
{ (float)ln	# (float) ln(%0) }
{ (float)log:(float)	# (float) log(%0) }
{ (float)raisedTo:(float)	# (float) raiseToPower(%0, %1) }
{ (float)raisedToInteger:(float)	# (float) raiseToPointInt(%0, %1) 
}
{ (float)sin	# (float) sin(%0) }
{ (float)sqrt	# (float) sqrt(%0) }
{ (float)squared	# (float) '%0*%0' }
{ (float)tan	# (float) tan(%0) }
{ (float)even	# (float) '(%0 & 1) == 0' }
{ (float)negative	# (float) '-%0' }
{ (float)odd	# (float) '(%0 & 1) != 0' }
{ (float)positive	# (float) '%0 >= 0' }
{ (float)sign	# (float) '%0 < 0' }
{ (float)strictlyPositive	# (float) '%x > 0' }
{ (float)ceiling	# (float) ceil(%0) }
{ (float)floor	# (float) floor(%0) }
{ (float)rounded	# (int) '(int)(%0+.5)' }
{ (float)roundTo:(float)	# (float) roundTo(%0, %1) }
{ (float)truncated	# (int) '((int)%0)' }
{ (float)truncateTo:(float)	# (float) truncateTo(%0, %1) }
{ (float)coerce:(float)	# (float) coerce(%0, %1) }
{ (float)generality	# (int) generality(%0) }
{ (float)retry:(BLOCK) coercing:(float)	# (float) retryCoercing(%0, %1, %2) }
{ (float)@ (float)	# (PT) 'pt((int)%0, (int)%1)' }
{ (float)asInteger	# (int) '(int)(%0)' }
{ (float)asPoint	# (float) 'pt((int)(%0), (int)(%0))' }
{ (float)degreesToRadians	# (float) degreesToRadians(%0) }
{ (int)degreesToRadians	# (float) 'degreesToRadians((float)(%0))' }
{ (float)radiansToDegrees	# (float) radiansToDegrees(%0) }
{ (int)radiansToDegrees	# (float) 'radiansToDegrees((float)(%0))' }
{ (float)to:(float)	# (float) to(%0, %1) }
{ (float)to:(float) by:(float)	# (float) toBy(%0, %1, %2) }
{ (float)to:(float) by:(float) do:(BLOCK)	# (float) 'for (x = %0; x < %1; x += %2) %3' 
}
{ (float)to:(float) do:(BLOCK)	# (float) 'for(x = %0; x < %1; x++) %2' 
}
{ (float)storeOn:(IOD)	# (float) storeOn(%0, %1) }
{ (float)readFrom:(IOD)	# (float) readFrom(%0, %1) }

"Misc.rules=================================================================="
{ (id)= (id) # (BOOL) '[%0 isEqual:%1]' } "Which is == and which isEqual?"
{ (int)= (int) # (BOOL) '%0 == %1' }
{ (int)= (float) # (BOOL) '%0 == %1' }
{ (float)= (int) # (BOOL) '%0 == %1' }
{ (BOOL)= (BOOL) # (BOOL) '%0 == %1' }
{ (id)== (id) # (BOOL) '%0 == %1' } "Which is == and which isEqual?"
{ (int)== (int) # (BOOL) '%0 == %1' }
{ (int)== (float) # (BOOL) '%0 == %1' }
{ (float)== (float) # (BOOL) '%0 == %1' }
{ (BOOL)== (BOOL) # (BOOL) '%0 == %1' }
{ associationsDo:(BLOCK) # 'for(seq = [[%0 associations] eachElement]; obj = [seq next]; ) %1' }

"Point.rules=================================================================="
{ (PT)x 		# (int)	'ptX(%0)' }
{ (PT)y 		# (int)	'ptY(%0)' }
{ (PT)x: (int)	# (PT) 'ptX(%0)=%1' }
{ (PT)y: (int)	# (PT) 'ptY(%0)=%1' }
{ (PT)< (int)	# (BOOL) 'ptIsLess(%0, %1)' }
{ (PT)<= (int)	# (BOOL) 'ptIsLessOrEqual(%0, %1)' }
{ (PT)= (int)	# (BOOL) 'ptIsEqual(%0, %1)' }
{ (PT)> (int)	# (BOOL) 'ptIsGreater(%0, %1)' }
{ (PT)>= (int)	# (BOOL) 'ptIsGreaterOrEqual(%0, %1)' }
{ (PT) hash 	# (int) '%0' }
{ (PT) hashMappedBy:(int)	# (PT) '%0' }
{ (int) max:(int)	# (int) 'min(%0, %1)' }
{ (int) min:(int)	# (int) 'max(%0, %1)' }
{ (float) max:(float)	# (float) 'min(%0, %1)' }
{ (float) min:(float)	# (float) 'max(%0, %1)' }
{ (PT) max:(PT)	# (PT) 'ptMax(%0, %1)' }
{ (PT) min:(PT)	# (PT) 'ptMin(%0, %1)' }
{ (PT) * (PT)	# (PT) 'ptTimes(%0, %1)' }
{ (PT) + (PT)	# (PT) 'ptPlus(%0, %1)' }
{ (PT) - (PT)	# (PT) 'ptMinus(%0, %1)' }
{ (PT) /(PT)	# (PT) 'ptSlash(%0, %1)' }
{ (PT) // (PT)	# (PT) 'ptSlashSlash(%0, %1)' }
{ (PT) * (int)	# (PT) 'ptTimesInt(%0, %1)' }
{ (PT) + (int)	# (PT) 'ptPlusInt(%0, %1)' }
{ (PT) - (int)	# (PT) 'ptMinusInt(%0, %1)' }
{ (PT) / (int)	# (PT) 'ptSlashInt(%0, %1)' }
{ (PT) // (int)	# (PT) 'ptSlashSlashInt(%0, %1)' }
{ (PT) abs 	# (PT) 'ptAbs(%0)' }
{ (PT) rounded	# (PT) '%0' }
{ (PT) truncateTo:(PT)	# (PT) 'ptTrunc(%0, %1)' }
{ (PT) r	# (PT) 'r(%0)' }
{ (PT) theta	# (int) 'ptTheta(%0)' }
{ (PT) dist:(PT)	# (int) 'ptDist(%0, %1)' }
{ (PT) dotProduct:(PT)	# (PT) 'ptDotProduct(%0, %1)' }
{ (PT) grid:(PT)	# (PT) 'ptGrid(%0, %1)' }
{ (PT) normal 	# (PT) 'ptNormal(%0)' }
{ (PT) pointNearestLine:(PT) to:(PT)	# (PT) 'ptNearestLine(%0, %1, %2)' }
{ (PT) transpose	# (PT) 'ptTranspose(%0, %1)' }
{ (PT) truncatedGrid:(PT)	# (PT) 'ptTruncatedGrid(%0, %1)' }
{ (PT) unitVector	# (PT) 'ptUnitVector(%0)' }
{ (PT) asPoint	# (PT) '%0' }
{ (PT) corner:(PT)	# (id) '[Rectangle origin:%0 corner:%1]' }
{ (PT) extent:(PT)	# (id) '[Rectangle origin:%0 extent:%1]' }
{ (id) extent:(PT)	# (id) '[%0 extent:%1]' }
{ (PT) coerce:(int)	# (PT) 'ptCoerce(%0, %1)' }
{ (PT) generality	# (int) 'ptGenerality(%0, %1)' }
{ (PT) scaleBy:(PT)	# (PT) 'ptScaleBy(%0, %1)' }
{ (PT) translateBy:(PT)	# (PT) 'ptPlus(%0, %1)' }
{ (PT) deepCopy	# (PT) '%0' }
{ (PT) shallowCopy	# (PT) '%0' }
{ (PT) printOn:(PT)	# (PT) 'ptPrn(%0)' }
{ (PT) storeOn:(PT)	# (PT) 'ptPrn(%0)' }

"DisplayObjects.rules========================================================"
{ # (float)	[direction] }
{ # (BOOL)	[contains:aRectangle] }
{ # (BOOL)	[containsPoint:(PT)aPoint] }
{ # (BOOL)	[cursorEnterView] }
{ # (BOOL)	[cursorExitView] }
{ # (BOOL)	[cursorMove] }
{ # (BOOL)	[cursorStill] }
{ # (BOOL)	[doEvent] }
{ # (BOOL)	[eventStillOcurring] }
{ # (BOOL)	[intersects:aRectangle] }
{ # (BOOL)	[isEqual:aRectangle] }
{ # (BOOL)	[isLocked] }
{ # (BOOL)	[isSelectionSelected] }
{ # (BOOL)	[isTopView] }
{ # (BOOL)	[isUnlocked] }
{ # (BOOL)	[keyboardEvent] }
{ # (BOOL)	[leftButtonDown] }
{ # (BOOL)	[leftButtonUp] }
{ # (BOOL)	[middleButtonDown] }
{ # (BOOL)	[middleButtonUp] }
{ # (BOOL)	[noscale] }
{ # (BOOL)	[rightButtonDown] }
{ # (BOOL)	[rightButtonUp] }
{ # (BOOL)	[timeoutEvent] }
{ # (BOOL)	[windowChangedEvent] }
{ # (BOOL)	[anyButtonChanged] }
{ # (BOOL)	[anyButtonDown] }
{ # (BOOL)	[contains:aRectangle] }
{ # (BOOL)	[containsPoint:(PT)aPoint] }
{ # (BOOL)	[intersects:r] }
{ # (BOOL)	[isContainedBy:aRectangle] }
{ # (BOOL)	[isEqual:aRectangle] }
{ # (BOOL)	[leftButtonChanged] }
{ # (BOOL)	[leftButtonDown] }
{ # (BOOL)	[leftButtonUp] }
{ # (BOOL)	[middleButtonChanged] }
{ # (BOOL)	[middleButtonDown] }
{ # (BOOL)	[middleButtonUp] }
{ # (BOOL)	[noButtonChanged] }
{ # (BOOL)	[noButtonDown] }
{ # (BOOL)	[rightButtonChanged] }
{ # (BOOL)	[rightButtonDown] }
{ # (BOOL)	[rightButtonUp] }
{ # (BYTE)	[readEvent] }
{ # (id)	[asForm] }
{ # (id)	[destinationForm] }
{ # (id)	[form] }
{ # (id)	[mask] }
{ # (int)	[outputMedium] }
{ # (PT)	[amountToTranslateWithin:aRectangle] }
{ # (PT)	[applyInverseTo:(PT)aPoint] }
{ # (PT)	[applyTo:(PT)aPoint] }
{ # (PT)	[bottomCenter] }
{ # (PT)	[bottomLeft] }
{ # (PT)	[bottomRight] }
{ # (PT)	[center] }
{ # (PT)	[centerLeft] }
{ # (PT)	[centerRight] }
{ # (PT)	[corner] }
{ # (PT)	[extent] }
{ # (PT)	[origin] }
{ # (PT)	[scale] }
{ # (PT)	[topCenter] }
{ # (PT)	[topLeft] }
{ # (PT)	[topRight] }
{ # (PT)	[translation] }
{ # (PT)	[amountToTranslateWithin:aRectangle] }
{ # (PT)	[bottomCenter] }
{ # (PT)	[bottomLeft] }
{ # (PT)	[bottomRight] }
{ # (PT)	[center] }
{ # (PT)	[centerLeft] }
{ # (PT)	[centerRight] }
{ # (PT)	[corner] }
{ # (PT)	[extent] }
{ # (PT)	[location] }
{ # (PT)	[origin] }
{ # (PT)	[topCenter] }
{ # (PT)	[topLeft] }
{ # (PT)	[topRight] }
{ # (PT)	[waitButton] }
{ # (id)	[boundingBox] }
{ # (id)	[clippingRectangle] }
{ # (id)	[compositionRectangle] }
{ # (id)	[computeBoundingBox] }
{ # (id)	[frame] }
{ # (id)	[visibleRectangle] }
{ # (int)	[rule] }
{ # (STR)	[string] }
{ # (STYLE)	[alignment] }
{ # (id)	[openAt:p] }
{ # (id)	[takeControl:p] }
{ # (int)	[area] }
{ # (int)	[bottom] }
{ # (int)	[fileDescriptor] }
{ # (int)	[hash] }
{ # (int)	[hashMappedBy:map] }
{ # (int)	[height] }
{ # (int)	[left] }
{ # (int)	[lineGrid] }
{ # (int)	[numberOfLines] }
{ # (int)	[paddingWidth] }
{ # (int)	[right] }
{ # (int)	[top] }
{ # (int)	[valueAt:(PT)aPoint] }
{ # (int)	[width] }
{ # (int)	[baseline] }
{ # (int)	[bottom] }
{ # (int)	[composeAll] }
{ # (int)	[compositionRectangleDelta] }
{ # (int)	[count] }
{ # (int)	[dyForPoint:(PT)pt] }
{ # (int)	[fileDescriptor] }
{ # (int)	[firstIndent] }
{ # (int)	[firstIndex] }
{ # (int)	[hash] }
{ # (int)	[hashMappedBy:map] }
{ # (int)	[height] }
{ # (int)	[indexOf:aSomething] }
{ # (int)	[lastIndex] }
{ # (int)	[left] }
{ # (int)	[leftMarginForCompositionForLine:(int)lineIndex] }
{ # (int)	[leftMarginForDisplayForLine:(int)lineIndex] }
{ # (int)	[leftMarginTabAt:(int)anInt] }
{ # (int)	[lineGrid] }
{ # (int)	[lineIndexOfCharacterIndex:(int)characterIndex] }
{ # (int)	[lineIndexOfTop:(int)top] }
{ # (int)	[lines:anArray] }
{ # (int)	[marginTabsLevel] }
{ # (int)	[numberOfLines] }
{ # (int)	[restIndent] }
{ # (int)	[right] }
{ # (int)	[rightIndent] }
{ # (int)	[rightMarginForComposition] }
{ # (int)	[rightMarginForDisplay] }
{ # (int)	[rightMarginTabAt:(int)huh] }
{ # (int)	[rightX] }
{ # (int)	[senseDelay:(int)msec] }
{ # (int)	[senseDelay:time] }
{ # (int)	[top] }
{ # (int)	[topAtLineIndex:(int)lineIndex] }
{ # (int)	[valueAt:(PT)aPoint] }
{ # (int)	[width] }
{ # (BITS)	[bits] }
{ # (id)	[align:(PT)aPoint1 with:(PT)aPoint2] }
{ # (id)	[append:aLink] }
{ # (id)	[area:aRectangle] }
{ # (id)	[areasDiffering:aRectangle] }
{ # (id)	[areasOutside:aRectangle] }
{ # (id)	[asParagraph] }
{ # (id)	[asString] }
{ # (id)	[asText] }
{ # (id)	[backgroundAt:(PT)aPoint] }
{ # (id)	[beCursor] }
{ # (id)	[black] }
{ # (id)	[black:aRectangle] }
{ # (id)	[border:aRectangle width:(int)borderWidth] }
{ # (id)	[border:aRectangle width:(int)borderWidth mask:aHalfTone] }
{ # (id)	[border:aRectangle widthRectangle:insets mask:aHalfTone] }
{ # (id)	[border:aRectangle widthRectangle:insets mask:aHalfTone clipBy:aClipRectList] }
{ # (id)	[borderWidth:(int)aWidth] }
{ # (id)	[borderWidth:(int)aWidth mask:aMask] }
{ # (id)	[bottom:(int)anInteger] }
{ # (id)	[boundingBox] }
{ # (id)	[centerX:(int)anInteger] }
{ # (id)	[centerY:(int)anInteger] }
{ # (id)	[centered] }
{ # (id)	[characterBlockAtPoint:(PT)aPoint] }
{ # (id)	[characterBlockForIndex:(int)targetIndex] }
{ # (id)	[clearIndents] }
{ # (id)	[clearVisibleRectangle] }
{ # (id)	[clipHeight:(int)anInteger] }
{ # (id)	[clipList] }
{ # (id)	[clipList:aClipRectList] }
{ # (id)	[clipWidth:(int)anInteger] }
{ # (id)	[clipX:(int)anInteger] }
{ # (id)	[clipY:(int)anInteger] }
{ # (id)	[clippingRectangle:aRectangle] }
{ # (id)	[color:ignored] }
{ # (id)	[combinationRule:(int)anInteger] }
{ # (id)	[composeForm] }
{ # (id)	[compositionRectangle:compRectangle] }
{ # (id)	[compositionRectangle:compositionRect text:aText style:aTextStyle offset:(PT)aPoint outputMedium:(int)aSymbol fitWidth:(BOOL)aBoolean] }
{ # (id)	[computeBoundingBox] }
{ # (id)	[convexShapeFill:aMask] }
{ # (id)	[copyBits] }
{ # (id)	[copyBitsAgain] }
{ # (id)	[copyFrom:(PT)sourcePoint to:(PT)destPoint extent:(PT)extentPoint form:sourceForm clipBy:aClipRectList rule:(int)rule mask:halftoneForm] }
{ # (id)	[copyFromArea:destRectangle toPoint:(PT)destPoint form:sourceForm clipBy:aClipRectList rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[copyFromArea:sourceRect toPoint:(PT)destOrigin form:sourceForm clipBy:aClipRectList rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[copyFromArea:sourceRect toPoint:(PT)destOrigin form:sourceForm clipBy:aClipRectList rule:(int)rule mask:aForm] }
{ # (id)	[copyFromArea:sourceRect toPoint:(PT)destOrigin form:sourceForm clipBy:aClipRectList rule:(int)rule mask:halftoneForm] }
{ # (id)	[copyLinesFrom:(int)firstIndex to:(int)lastIndex] }
{ # (id)	[copyStr:(STR)sourceString font:aFont at:(PT)destOrigin clipBy:aClipRectList rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[copyToArea:destRectangle fromPoint:(PT)destPoint form:sourceForm rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[copyToArea:destRectangle fromPoint:(PT)sourcePt form:sourceForm rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[copyToArea:destRectangle fromPoint:(PT)sourcePt form:sourceForm rule:(int)rule mask:halftoneForm] }
{ # (id)	[corner:(PT)c1 corner:(PT)c2] }
{ # (id)	[corner:(PT)cornerPoint] }
{ # (id)	[cursorLink:(BOOL)yesno] }
{ # (id)	[darkGray] }
{ # (id)	[darkGray:aRectangle] }
{ # (id)	[deepCopy] }
{ # (id)	[defaultNib:(int)widthInteger] }
{ # (id)	[deltaMarginTabsLevel:(int)anInteger] }
{ # (id)	[destForm:aForm] }
{ # (id)	[destForm:df sourceForm:sf halftoneForm:hf combinationRule:(int)rule destOrigin:(PT)destOriginPoint sourceOrigin:(PT)sourceOriginPoint extent:(PT)anExtent clipList:aClipRectList] }
{ # (id)	[destOrigin:(PT)aPoint] }
{ # (id)	[destRect:aRectangle] }
{ # (id)	[destX:(int)anInteger] }
{ # (id)	[destY:(int)anInteger] }
{ # (id)	[destinationForm:aFormOrRectangle] }
{ # (id)	[display] }
{ # (id)	[displayAt:(PT)aDisplayPoint] }
{ # (id)	[displayAt:(PT)aPoint] }
{ # (id)	[displayCaretAt:(PT)aPoint] }
{ # (id)	[displayCaretAt:(PT)aPoint andClip:clipBox] }
{ # (id)	[displayCaretForBlock:aCharacterBlock] }
{ # (id)	[displayLinesFrom:(int)firstIndex to:(int)lastIndex] }
{ # (id)	[displayOn:aDisplay transformation:displayTransformation clipBy:aClipRectList align:(PT)alignmentPoint with:(PT)relativePoint rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[displayOn:aDisplayMedium] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint clipBy:aClipRectList] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint clipBy:aClipRectList rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint clipBy:aClipRectList rule:(int)combinationRule mask:maskForm] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint clipBy:aClipRectList rule:(int)ruleInteger mask:aForm] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint clipBy:aClipRectList rule:(int)ruleInteger mask:aForm] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint rule:(int)ruleInteger] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:aClipRectList] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:aClipRectList align:(PT)alignmentPoint with:(PT)relativePoint] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:aClipRectList align:(PT)alignmentPoint with:(PT)relativePoint rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:aClipRectList align:(PT)alignmentPoint with:(PT)relativePoint rule:(int)ruleInteger mask:aForm] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:aClipRectList align:(PT)alignmentPoint with:(PT)relativePoint rule:(int)ruleInteger mask:aForm] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:aClipRectList fixedPoint:(PT)aPoint] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:aClipRectList rule:(int)ruleInteger mask:aForm] }
{ # (id)	[dotOfSize:(int)diameter] }
{ # (id)	[down] }
{ # (id)	[dragon:(int)order] }
{ # (id)	[drawFrom:(PT)startPoint to:(PT)stopPoint] }
{ # (id)	[drawLine:sourceForm from:(PT)beginPoint to:(PT)endPoint clipBy:aClipRectList rule:(int)anInteger mask:aForm] }
{ # (id)	[drawLine:sourceForm from:(PT)beginPoint to:(PT)endPoint clipBy:aClipRectList rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[drawLineAround:aRectangle clipBy:cr rule:(int)combinationRule] }
{ # (id)	[drawLineFrom:(PT)bp to:(PT)ep clipBy:aClipRectList rule:(int)combinationRule] }
{ # (id)	[drawLineFrom:(PT)bp to:(PT)ep clipBy:aClipRectList rule:(int)rule] }
{ # (id)	[drawLoopDeltaX:(int)xDelta deltaY:(int)yDelta] }
{ # (id)	[example] }
{ # (id)	[expandByInt:(int)delta] }
{ # (id)	[expandByPoint:(PT)delta] }
{ # (id)	[expandByRectangle:aRectangle] }
{ # (id)	[extent:(PT)aPoint] }
{ # (id)	[extent:(PT)anExtent figureBits:(BITS)figureBits shapeBits:(BITS)shapeBits] }
{ # (id)	[extent:(PT)extentPoint] }
{ # (id)	[extent:(PT)extentPoint bits:(BITS)theBits] }
{ # (id)	[figure] }
{ # (id)	[figure:figureForm shape:shapeForm] }
{ # (id)	[filberts:(int)n side:(int)s] }
{ # (id)	[fill:aRectangle] }
{ # (id)	[fill:aRectangle mask:aForm] }
{ # (id)	[fill:aRectangle rule:(int)anInteger mask:aForm] }
{ # (id)	[fill:aRectangle rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[fill:aRectangle rule:(int)combinationRule mask:halftoneForm clipBy:aClipRectList] }
{ # (id)	[fillIn:aBlock] }
{ # (id)	[first] }
{ # (id)	[firstIndent:(int)anInteger] }
{ # (id)	[fit] }
{ # (id)	[flash] }
{ # (id)	[flash:aRectangle] }
{ # (id)	[follow:locationBlock while:durationBlock] }
{ # (id)	[form] }
{ # (id)	[frame:aClipRectList] }
{ # (id)	[free] }
{ # (id)	[freeAll] }
{ # (id)	[fromDisplay:aRectangle] }
{ # (id)	[fromUser] }
{ # (id)	[fromUser:(PT)aPoint] }
{ # (id)	[fromUser:(PT)gridPoint] }
{ # (id)	[fromUser:(PT)originPoint] }
{ # (id)	[fromUserAspectRatio:(PT)aspectPoint] }
{ # (id)	[go:distance] }
{ (id)go:(int) # (id)	'[%0 go:(float)(distance)]' }
{ (id)go:(float) # (id)	'[%0 go:distance]' }
{ # (id)	[goto:(PT)aPoint] }
{ # (id)	[gray] }
{ # (id)	[gray:aRectangle] }
{ # (id)	[gridWithLead:(int)leadInteger] }
{ # (id)	[height:(int)anInteger] }
{ # (id)	[height:(int)heightInteger] }
{ # (id)	[hilbert:n side:s] }
{ # (id)	[hilberts:(int)n] }
{ # (id)	[home] }
{ # (id)	[initialize] }
{ # (id)	[insert:aLink] }
{ # (id)	[insetByInt:(int)delta] }
{ # (id)	[insetByPoint:(PT)delta] }
{ # (id)	[insetByRectangle:aRectangle] }
{ # (id)	[insetDisplayBox] }
{ # (id)	[insetOriginBy:(PT)originDeltaPoint cornerBy:(PT)cornerDeltaPoint] }
{ # (id)	[intersect:r] }
{ # (id)	[justified] }
{ # (id)	[last] }
{ # (id)	[left:(int)aLeft top:(int)aTop width:(int)aWidth height:(int)aHeight] }
{ # (id)	[left:(int)anInteger] }
{ # (id)	[left:(int)left top:(int)top right:(int)right bottom:(int)bottom] }
{ # (id)	[left:(int)leftNumber right:(int)rightNumber top:(int)topNumber bottom:(int)bottomNumber] }
{ # (id)	[leftFlush] }
{ # (id)	[lightGray] }
{ # (id)	[lightGray:aRectangle] }
{ # (id)	[lineAt:(int)indexInteger put:aTextLineInterval] }
{ # (id)	[lineAt:(int)lineIndex] }
{ # (id)	[lines] }
{ # (id)	[linkAt:(int)anInt] }
{ # (id)	[lock] }
{ # (id)	[lock:aRectangle] }
{ # (id)	[magnifyBy:(PT)scale] }
{ # (id)	[mandala:(int)npoints diameter:(int)d] }
{ # (id)	[marginTabsLevel:(int)anInteger] }
{ # (id)	[mask:aForm] }
{ # (id)	[mask:maskForm] }
{ # (id)	[merge:r] }
{ # (id)	[mergeWith:r] }
{ # (id)	[mouseSelect:previousStartBlock to:previousStopBlock] }
{ # (id)	[moveBy:(PT)aPoint] }
{ # (id)	[moveBy:(PT)aPoint with:aClipRectList] }
{ # (id)	[moveBy:(int)aPoint] }
{ # (id)	[moveTo:(PT)aPoint] }
{ # (id)	[moveTo:(PT)newLoc restoring:background] }
{ # (id)	[new] }
{ # (id)	[north] }
{ # (id)	[offset:(PT)aPoint] }
{ # (id)	[origin:(PT)aPoint] }
{ # (id)	[origin:(PT)op corner:(PT)cp] }
{ # (id)	[origin:(PT)originPoint] }
{ # (id)	[origin:(PT)originPoint corner:(PT)cornerPoint] }
{ # (id)	[origin:(PT)originPoint extent:(PT)extentPoint] }
{ # (id)	[origin:(PT)originPoint extent:(PT)extentPoint bits:(BITS)theBits] }
{ # (id)	[origin:(PT)originPoint extent:(PT)extentPoint window:(int)aFd] }
{ # (id)	[originFromUser:(PT)extentPoint] }
{ # (id)	[originFromUser:(PT)extentPoint grid:(int)scaleFactor] }
{ # (id)	[outline] }
{ # (id)	[outputMedium:(int)aSymbol] }
{ # (id)	[paintBits] }
{ # (id)	[place:(PT)aPoint] }
{ # (id)	[predecessorOf:aLink] }
{ # (id)	[print] }
{ # (id)	[putEventBack] }
{ # (id)	[receiver:anObject selector:(SEL)aSelector] }
{ # (id)	[recomposeIn:compositionRect clipBy:clippingRect] }
{ # (id)	[relativeRectangle] }
{ # (id)	[remove:aLink] }
{ # (id)	[removeFirstChars:numberOfChars] }
{ # (id)	[replaceFrom:(int)start to:(int)stop with:aText displaying:(BOOL)displayBoolean] }
{ # (id)	[repositionAt:(PT)aPoint clipBy:clippingBox] }
{ # (id)	[resetLocks] }
{ # (id)	[restIndent:(int)anInteger] }
{ # (id)	[reverse] }
{ # (id)	[reverse:aRectangle] }
{ # (id)	[reverse:aRectangle mask:aMask] }
{ # (id)	[reverseFrom:characterBlock1 to:characterBlock2] }
{ # (id)	[reverseFrom:characterBlock1 to:characterBlock2 andClip:clipBox] }
{ # (id)	[reverseRectangle:aRectangle] }
{ # (id)	[right:(int)anInteger] }
{ # (id)	[rightFlush] }
{ # (id)	[rightIndent:(int)anInteger] }
{ # (id)	[rounded] }
{ # (id)	[rule:(int)ruleInteger] }
{ # (id)	[scaleBy:(int)scale] }
{ # (id)	[scrollBy:(int)height grid:(int)grid] }
{ # (id)	[scrollBy:(int)heightToMove] }
{ # (id)	[selectWord:stringIndex] }
{ # (id)	[senseAllButtons:(BOOL)onoff] }
{ # (id)	[senseLeftButton:(BOOL)onoff] }
{ # (id)	[senseMiddleButton:(BOOL)onoff] }
{ # (id)	[senseMove:(BOOL)onoff] }
{ # (id)	[senseMoveWhileButtonDown:(BOOL)onoff] }
{ # (id)	[senseRightButton:(BOOL)onoff] }
{ # (id)	[senseStill:(BOOL)onoff] }
{ # (id)	[senseWindowEnter:(BOOL)onoff] }
{ # (id)	[senseWindowExit:(BOOL)onoff] }
{ # (id)	[setFigure:figureForm shape:shapeForm] }
{ # (id)	[setInputMasks] }
{ # (id)	[setMask:(int)anEventMask to:(BOOL)onoff] }
{ # (id)	[shape] }
{ # (id)	[shape:aSolidForm] }
{ # (id)	[sourceForm:aForm] }
{ # (id)	[sourceOrigin:(PT)aPoint] }
{ # (id)	[sourceRect:aRectangle] }
{ # (id)	[sourceX:(int)anInteger] }
{ # (id)	[sourceY:(int)anInteger] }
{ # (id)	[spiral:(int)n angle:(float)a] }
{ # (id)	[str:(STR)sourceString font:aFont at:(PT)destOrigin rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[successor] }
{ # (id)	[successor:aLink] }
{ # (id)	[text] }
{ # (id)	[text:aText] }
{ # (id)	[text:aText textStyle:aTextStyle] }
{ # (id)	[text:aText textStyle:aTextStyle offset:(PT)aPoint] }
{ # (id)	[textAt:(int)lineIndex] }
{ # (id)	[textStyle] }
{ # (id)	[textStyle:aTextStyle] }
{ # (id)	[toReverse:aRectangle] }
{ # (id)	[toggleAlignment] }
{ # (id)	[top:(int)anInteger] }
{ # (id)	[trackFunction:(IMP)aTrackingFunction] }
{ # (id)	[translateBy:(PT)aPoint] }
{ # (id)	[translateByInt:(int)factor] }
{ # (id)	[trimLinesTo:(int)lastLineInteger] }
{ (id)turn:(int) # (id)	'[%0 turn:((float)%1)]' }
{ (id)turn:(float) # (id)	'[%0 turn:%1]' }
{ # (id)	[unlock] }
{ # (id)	[up] }
{ # (id)	[updateCompositionHeight] }
{ # (id)	[updateOrigin:(PT)anOrigin extent:(PT)anExtent] }
{ # (id)	[value] }
{ # (id)	[valueAt:(PT)aPoint put:(int)bitValue] }
{ # (id)	[valueAt:(PT)aPoint put:(int)value] }
{ # (id)	[veryLightGray] }
{ # (id)	[veryLightGray:aRectangle] }
{ # (id)	[waitButton] }
{ # (id)	[waitNoButton] }
{ # (id)	[white] }
{ # (id)	[white:aRectangle] }
{ # (id)	[width:(int)anInteger] }
{ # (id)	[width:(int)widthInteger] }
{ # (id)	[windowChanged] }
{ # (id)	[with:aForm] }
{ # (id)	[withText:aText] }
{ # (id)	[withText:aText style:aTextStyle] }
{ # (id)	[withText:aText style:aTextStyle compositionRectangle:compRect clippingRectangle:aClipRectList] }



{ # (BOOL)	[contains:(id)aRectangle] }
{ # (BOOL)	[intersects:(id)aRectangle] }
{ # (BOOL)	[contains:(id)aRectangle] }
{ # (BOOL)	[intersects:(id)r] }
{ # (BOOL)	[isContainedBy:(id)aRectangle] }
{ # (PT)	[amountToTranslateWithin:(id)aRectangle] }
{ # (id)	[boundingBox] }
{ # (id)	[clippingRectangle] }
{ # (id)	[compositionRectangle] }
{ # (id)	[computeBoundingBox] }
{ # (id)	[frame] }
{ # (id)	[visibleRectangle] }
{ # (id)	[area:(id)aRectangle] }
{ # (id)	[areasDiffering:(id)aRectangle] }
{ # (id)	[areasOutside:(id)aRectangle] }
{ # (id)	[black:(id)aRectangle] }
{ # (id)	[border:(id)aRectangle width:(int)borderWidth] }
{ # (id)	[border:(id)aRectangle width:(int)borderWidth mask:aHalfTone] }
{ # (id)	[border:(id)aRectangle widthRectangle:(id)insets mask:aHalfTone] }
{ # (id)	[border:(id)aRectangle widthRectangle:(id)insets mask:aHalfTone clipBy:(id)aClipRectList] }
{ # (id)	[clipList:(id)aClipRectList] }
{ # (id)	[clippingRectangle:(id)aRectangle] }
{ # (id)	[compositionRectangle:(id)compRectangle] }
{ # (id)	[compositionRectangle:(id)compositionRect text:aText style:aTextStyle offset:(PT)aPoint outputMedium:(int)aSymbol fitWidth:(BOOL)aBoolean] }
{ # (id)	[copyFrom:(PT)sourcePoint to:(PT)destPoint extent:(PT)extentPoint form:sourceForm clipBy:(id)aClipRectList rule:(int)rule mask:halftoneForm] }
{ # (id)	[copyFromArea:(id)destRectangle toPoint:(PT)destPoint form:sourceForm clipBy:(id)aClipRectList rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[copyFromArea:(id)sourceRect toPoint:(PT)destOrigin form:sourceForm clipBy:(id)aClipRectList rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[copyFromArea:(id)sourceRect toPoint:(PT)destOrigin form:sourceForm clipBy:(id)aClipRectList rule:(int)rule mask:aForm] }
{ # (id)	[copyFromArea:(id)sourceRect toPoint:(PT)destOrigin form:sourceForm clipBy:(id)aClipRectList rule:(int)rule mask:halftoneForm] }
{ # (id)	[copyStr:(STR)sourceString font:aFont at:(PT)destOrigin clipBy:(id)aClipRectList rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[copyToArea:(id)destRectangle fromPoint:(PT)destPoint form:sourceForm rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[copyToArea:(id)destRectangle fromPoint:(PT)sourcePt form:sourceForm rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[copyToArea:(id)destRectangle fromPoint:(PT)sourcePt form:sourceForm rule:(int)rule mask:halftoneForm] }
{ # (id)	[darkGray:(id)aRectangle] }
{ # (id)	[destForm:df sourceForm:sf halftoneForm:hf combinationRule:(int)rule destOrigin:(PT)destOriginPoint sourceOrigin:(PT)sourceOriginPoint extent:(PT)anExtent clipList:(id)aClipRectList] }
{ # (id)	[destRect:(id)aRectangle] }
{ # (id)	[displayCaretAt:(PT)aPoint andClip:(id)clipBox] }
{ # (id)	[displayOn:aDisplay transformation:displayTransformation clipBy:(id)aClipRectList align:(PT)alignmentPoint with:(PT)relativePoint rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint clipBy:(id)aClipRectList] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint clipBy:(id)aClipRectList rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint clipBy:(id)aClipRectList rule:(int)combinationRule mask:maskForm] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint clipBy:(id)aClipRectList rule:(int)ruleInteger mask:aForm] }
{ # (id)	[displayOn:aDisplayMedium at:(PT)aDisplayPoint clipBy:(id)aClipRectList rule:(int)ruleInteger mask:aForm] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:(id)aClipRectList] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:(id)aClipRectList align:(PT)alignmentPoint with:(PT)relativePoint] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:(id)aClipRectList align:(PT)alignmentPoint with:(PT)relativePoint rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:(id)aClipRectList align:(PT)alignmentPoint with:(PT)relativePoint rule:(int)ruleInteger mask:aForm] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:(id)aClipRectList align:(PT)alignmentPoint with:(PT)relativePoint rule:(int)ruleInteger mask:aForm] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:(id)aClipRectList fixedPoint:(PT)aPoint] }
{ # (id)	[displayOn:aDisplayMedium transformation:displayTransformation clipBy:(id)aClipRectList rule:(int)ruleInteger mask:aForm] }
{ # (id)	[drawLine:sourceForm from:(PT)beginPoint to:(PT)endPoint clipBy:(id)aClipRectList rule:(int)anInteger mask:aForm] }
{ # (id)	[drawLine:sourceForm from:(PT)beginPoint to:(PT)endPoint clipBy:(id)aClipRectList rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[drawLineAround:(id)aRectangle clipBy:(id)cr rule:(int)combinationRule] }
{ # (id)	[drawLineFrom:(PT)bp to:(PT)ep clipBy:(id)aClipRectList rule:(int)combinationRule] }
{ # (id)	[drawLineFrom:(PT)bp to:(PT)ep clipBy:(id)aClipRectList rule:(int)rule] }
{ # (id)	[expandByRectangle:(id)aRectangle] }
{ # (id)	[fill:(id)aRectangle] }
{ # (id)	[fill:(id)aRectangle mask:aForm] }
{ # (id)	[fill:(id)aRectangle rule:(int)anInteger mask:aForm] }
{ # (id)	[fill:(id)aRectangle rule:(int)combinationRule mask:halftoneForm] }
{ # (id)	[fill:(id)aRectangle rule:(int)combinationRule mask:halftoneForm clipBy:(id)aClipRectList] }
{ # (id)	[flash:(id)aRectangle] }
{ # (id)	[frame:(id)aClipRectList] }
{ # (id)	[fromDisplay:(id)aRectangle] }
{ # (id)	[gray:(id)aRectangle] }
{ # (id)	[insetByRectangle:(id)aRectangle] }
{ # (id)	[intersect:(id)r] }
{ # (id)	[lightGray:(id)aRectangle] }
{ # (id)	[lock:(id)aRectangle] }
{ # (id)	[merge:(id)r] }
{ # (id)	[mergeWith:(id)r] }
{ # (id)	[moveBy:(PT)aPoint with:(id)aClipRectList] }
{ # (id)	[recomposeIn:(id)compositionRect clipBy:(id)clippingRect] }
{ # (id)	[repositionAt:(PT)aPoint clipBy:(id)clippingBox] }
{ # (id)	[reverse:(id)aRectangle] }
{ # (id)	[reverse:(id)aRectangle mask:aMask] }
{ # (id)	[reverseRectangle:(id)aRectangle] }
{ # (id)	[sourceRect:(id)aRectangle] }
{ # (id)	[toReverse:(id)aRectangle] }
{ # (id)	[veryLightGray:(id)aRectangle] }
{ # (id)	[white:(id)aRectangle] }
{ # (id)	[withText:aText style:aTextStyle compositionRectangle:(id)compRect clippingRectangle:(id)aClipRectList] }
\Rogue\Monster\
else
  echo "will not over write ./rules/generic.ru"
fi
echo "Finished archive 5 of 5"
exit
----
Dieter H. Zebbedies ('dee-ter  ayech  'zeb-ed-eez)
 Zebb-Hoff Mach. Tool's Automated Manufacturing Project Cleveland, OH
 (USnail): 9535 Clinton Rd, Cleveland, OH 44144 (+216 631 6100) (+216 741-5994)
 (UUCP): ...{decvax,sun,cbosgd}!cwruecmp!zhmti!dieter
 (CSNET/ARPA/BITNET): dieter@CWRU.EDU