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.Ewildietz@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.EDUdietz@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.EDUdietz@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