home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume1 / 8708 / 31 < prev    next >
Encoding:
Internet Message Format  |  1990-07-13  |  33.9 KB

  1. From: dietz@zhmti.UUCP (Dieter H. Zebbedies)
  2. Newsgroups: comp.sources.misc
  3. Subject: "Producer" translates Smalltalk to Objective-C (Part 2 of 5)
  4. Message-ID: <4218@ncoast.UUCP>
  5. Date: 20 Aug 87 01:55:29 GMT
  6. Sender: allbery@ncoast.UUCP
  7. Organization: Zebb-Hoff Machine Tool Inc's Automated Mfg. Project, Cleve., OH
  8. Lines: 736
  9. Approved: allbery@ncoast.UUCP
  10. X-Archive: comp.sources.misc/8708/31
  11.  
  12. "Producer", A package to translate Smalltalk-80 code to your favorite
  13. object oriented language, Objective-C.
  14.  
  15. #!/bin/sh
  16. # to extract, remove the header and type "sh filename"
  17. if `test ! -d ./example`
  18. then
  19.   mkdir ./example
  20.   echo "mkdir ./example"
  21. fi
  22. if `test ! -s ./example/Makefile`
  23. then
  24. echo "writting ./example/Makefile"
  25. cat > ./example/Makefile << '\Rogue\Monster\'
  26. O= BounceInBoxNode.o 
  27. M= BounceInBoxNode.m 
  28. S= BounceInBoxNode.st 
  29. .SUFFIXES:
  30. .SUFFIXES: .m .st .o .i
  31. P=../src/producer -c
  32. R=../rules/generic.ru animation.ru
  33. X=objcc -c -I/u/cox/ui
  34. all: rm src
  35. rm:                    ; rm -f $M
  36. src: $M
  37. obj: $O
  38. stvd.a:    $O            ; ar ruv stvd.a $*
  39. .st.o:                ; $P $R $< >$*.m && $X $*.m
  40. .st.m:                ; -$P $R $< >$*.m
  41. .st.i:                ; $P -i $R $< >$*.i 2>&1
  42. .m.o:                ; $X $*.m
  43. wc:                    ; wc $S
  44. clean:                ; rm -f *.[mcoi] log core
  45. \Rogue\Monster\
  46. else
  47.   echo "will not over write ./example/Makefile"
  48. fi
  49. if `test ! -s ./example/BounceInBoxNode.st`
  50. then
  51. echo "writting ./example/BounceInBoxNode.st"
  52. cat > ./example/BounceInBoxNode.st << '\Rogue\Monster\'
  53. MovingNode subclass: #BounceInBoxNode
  54.     instanceVariableNames: ''
  55.     classVariableNames: ''
  56.     poolDictionaries: ''
  57.     category: 'Graphics-Animation'!
  58.  
  59. !BounceInBoxNode methodsFor: 'display'!
  60. displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle rule: 
  61.     ruleInteger mask: aForm
  62.     | relLoc |
  63.      super displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle 
  64.         rule: ruleInteger mask: aForm.
  65.     relLoc _ location + clipRectangle origin.
  66.     (velocity x < 0 and: [relLoc x < clipRectangle left])
  67.         ifTrue: [velocity _ velocity*(-1@1)].
  68.     (velocity x > 0 and: [(relLoc x+contents width) > clipRectangle right])
  69.         ifTrue: [velocity _ velocity*(-1@1)].
  70.     (velocity y < 0 and: [relLoc y < clipRectangle top])
  71.         ifTrue: [velocity _ velocity*(1@-1)].
  72.     (velocity y > 0 and: [(relLoc y+contents height) > clipRectangle bottom]
  73. )
  74.         ifTrue: [velocity _ velocity*(1@-1)].
  75. ! !
  76.  
  77. \Rogue\Monster\
  78. else
  79.   echo "will not over write ./example/BounceInBoxNode.st"
  80. fi
  81. if `test ! -s ./example/st80.h`
  82. then
  83. echo "writting ./example/st80.h"
  84. cat > ./example/st80.h << '\Rogue\Monster\'
  85. // Collecting.h:
  86. #ifndef VIDEOANIMATION_H
  87. #define VIDEOANIMATION_H
  88. #    include "DisplayObjects.h"
  89.  
  90. #    ifdef OBJC_COX
  91. #    define CATEGORIES()
  92. #    else
  93. #    define CATEGORIES() (VideoAnimation, DisplayObjects, Collecting, Primitive)
  94. #    endif
  95.  
  96. #endif
  97.  
  98.  
  99. \Rogue\Monster\
  100. else
  101.   echo "will not over write ./example/st80.h"
  102. fi
  103. if `test ! -s ./example/animation.ru`
  104. then
  105. echo "writting ./example/animation.ru"
  106. cat > ./example/animation.ru << '\Rogue\Monster\'
  107. { # BounceInBoxNode (id) BounceInBoxNode }
  108. { # DisplayObject (id) DisplayObject }
  109. { # EvaluationNode (id) EvaluationNode }
  110. { # MovingNode (id) MovingNode }
  111. { # PositionNode (id) PositionNode }
  112. { # SequenceNode (id) SequenceNode }
  113. { # SuperpositionNode (id) SuperpositionNode }
  114. { # WindowNode (id) WindowNode }
  115. { # aBlock (id) aBlock }
  116. { # aCollection (id) aCollection }
  117. { # aDisplayPoint (PT) aDisplayPoint }
  118. { # aForm (id) aForm }
  119. { # boundingBox (id) boundingBox }
  120. { # c (id) aCollection }
  121. { # clipRect (id) clipRect }
  122. { # clipRectangle (id) clipRectangle }
  123. { # contents (id) contents }
  124. { # destForm (id) destForm }
  125. { # evalBlock (id) evalBlock }
  126. { # index (int) index }
  127. { # l (PT) locationPoint }
  128. { # location (PT) location }
  129. { # node (id) node }
  130. { # position (PT) position }
  131. { # relLoc (PT) relLoc }
  132. { # ruleInteger (int) ruleInteger }
  133. { # subNodes (id) subNodes }
  134. { # v (PT) velocityPoint }
  135. { # velocity (PT) velocity }
  136. { # window (id) window }
  137.  
  138. { (id)displayOn:(id) at:(PT) clippingBox:(id) rule:(int) mask:(id) #
  139.     (id) [displayOn:%1 at:(PT)%2 clipBy:%3 rule:(int)%4 mask:%5] }
  140. { # [(id)at:(PT)pt] }
  141. { # [(id)contents:(id)a location:(PT)b ] }
  142. { # (id)[fixTemps] }
  143. { # (id)[setBlock:(id)a] }
  144. { # (id)[setContents:(id)a location:(PT)b] }
  145. { # (id)[setSubNodes:(id)a ] }
  146. { # (id)[setVelocity:(PT)a ] }
  147. { (id)setNodes:(id) index:(int) # (id)[setNodes:(id)nodeCollection index:(int)anInteger] }
  148. { (id)subNodes:(id) index:(int) # (id)[subNodes:(id)aCollection index:(int)anInteger] }
  149.  
  150. { # (BOOL)[anyButtonPressed] }
  151. { # (id)[block:(BLOCK)aBlock ] }
  152. { # (id)[contents:(id)aForm location:(PT)aPoint velocity:(PT)velocityPoint ] }
  153. { # (id)[displayView] }
  154. { # (id)[extent:(PT)anExtent fromArray:anArray offset:(PT)aPoint ] }
  155. { # (id)[model:(id)aModel ] }
  156. { # (PT)[mousePoint] }
  157. { # (RULE)[over] }
  158. { (id)pi # (float)'3.414' }
  159. { # (id)[release] }
  160. { # (id)[run:(id)aWindowNode ] }
  161. { # (id)[setWindow:(id)aWindow contents:(id)aCollection ] }
  162. { # (id)[spiral:(float)anAngle] }
  163. { # (id)[subNodes:(id)aNode ] }
  164. { # (id)[window:(id)aWindow contents:(id)aCollection ] }
  165. { (id)with:(id) with:(id) with:(id) # (id)'[%0 with:3, %1, %2, %3]' }
  166. { # n (int) n }
  167. { # (int)[collect:(BLOCK)aBlock ] }
  168. \Rogue\Monster\
  169. else
  170.   echo "will not over write ./example/animation.ru"
  171. fi
  172. if `test ! -s ./example/BounceInBoxNode.m`
  173. then
  174. echo "writting ./example/BounceInBoxNode.m"
  175. cat > ./example/BounceInBoxNode.m << '\Rogue\Monster\'
  176. // // MovingNode subclass: #BounceInBoxNode
  177. //     instanceVariableNames: ''
  178. //     classVariableNames: ''
  179. //     poolDictionaries: ''
  180. //     category: 'Graphics-Animation'!
  181.  
  182. #include "st80.h"
  183. = BounceInBoxNode:MovingNode CATEGORIES(){
  184. }
  185. // 
  186. // !BounceInBoxNode methodsFor: 'display'!
  187. // displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle rule: 
  188. //     ruleInteger mask: aForm
  189. //     | relLoc |
  190. //      super displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle 
  191. //         rule: ruleInteger mask: aForm.
  192. //     relLoc _ location + clipRectangle origin.
  193. //     (velocity x < 0 and: [relLoc x < clipRectangle left])
  194. //         ifTrue: [velocity _ velocity*(-1@1)].
  195. //     (velocity x > 0 and: [(relLoc x+contents width) > clipRectangle right])
  196. //         ifTrue: [velocity _ velocity*(-1@1)].
  197. //     (velocity y < 0 and: [relLoc y < clipRectangle top])
  198. //         ifTrue: [velocity _ velocity*(1@-1)].
  199. //     (velocity y > 0 and: [(relLoc y+contents height) > clipRectangle bottom]
  200. // )
  201. //         ifTrue: [velocity _ velocity*(1@-1)].
  202. // ! !
  203.  
  204. - displayOn:destForm at:(PT)aDisplayPoint clippingBox:clipRectangle rule:(int)ruleInteger mask:aForm {
  205.     PT relLoc;
  206.     [super displayOn:destForm at:aDisplayPoint clipBy:clipRectangle rule:ruleInteger mask:aForm];
  207.     relLoc = ptPlus(location, [clipRectangle origin]);
  208.     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)
  209.  
  210.  
  211.  < [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;
  212. }
  213. // 
  214. // \Rogue\Monster\
  215. else
  216.   echo "will not over write ./example/BounceInBoxNode.m"
  217. fi
  218. if `test ! -s ./log`
  219. then
  220. echo "writting ./log"
  221. cat > ./log << '\Rogue\Monster\'
  222. itroff -me mac.me doc.me
  223. .C 0-1 ""
  224. .H0 0-1 "Provisos"
  225. .H0 0-1 "How it works"
  226. .H0 0-2 "Status"
  227. .H0 0-3 "What's in this distribution"
  228. .H0 0-5 "Usage"
  229. ------ make doc.i
  230. \Rogue\Monster\
  231. else
  232.   echo "will not over write ./log"
  233. fi
  234. if `test ! -s ./producer.me`
  235. then
  236. echo "writting ./producer.me"
  237. cat > ./producer.me << '\Rogue\Monster\'
  238. .tp
  239. .po .5i
  240. .ll 7i
  241. .(l C
  242. \fB\s14Producer\s0\fP
  243.  
  244. \fIFrom the Prototyping Laboratory to the Production Line
  245. Translating Smalltalk-80 Applications to Objective-C\fP
  246.  
  247. Brad Cox, Ph.D.
  248. Productivity Products International
  249. Sandy Hook, CT 06497
  250. (203) 426 1875
  251.  
  252. For presentation at OOPSLA/86
  253. .)C
  254. .(q
  255. .hl
  256. .ce
  257. \fIAbstract\fP
  258. .sp
  259. This paper proposes that source to source translation tools could provide
  260. a way of integrating the strengths of production programming environments
  261. like C/Unix with rapid prototyping environments like Smalltalk-80 into a
  262. comprehensive hybrid environment that spans more of the software development
  263. life-spiral than ever before. It describes a tool-assisted process for
  264. translating Smalltalk-80 programs into Objective-C, and shows how the
  265. tool is used in practice.
  266. .hl
  267. .)q
  268. .he 'Producer''
  269. .fo 'Productivity Products International'Page %'\*(td'
  270. .(f
  271. \fIObjective-C, Software-IC, Vici\fP and \fIPPI\fP are trademarks of 
  272. Productivity Products International.
  273. .)f
  274. .(f
  275. \fISmalltalk-80\fP is a trademark of Xerox Corporation.
  276. .)f
  277. .(f
  278. \fIUnix\fP is a trademark of AT&T.
  279. .)f
  280. .pp
  281. Smalltalk-80 and C/Unix are very different tools that are optimized for 
  282. different jobs at opposite ends of the process for transforming raw ideas
  283. into commercial software products. To use an analogy from automobile 
  284. manufacturing, Smalltalk-80 is at its best in the design shop for building 
  285. prototypes from which next year's model can be visualized, and C/Unix are at
  286. their best on the production line for building cost-effective implementations 
  287. once the design has been proven through prototyping.
  288. .pp
  289. However it is becoming increasingly harder to maintain a strict separation
  290. between prototyping and production. Many production systems, particularly
  291. in CAD and office automation, are providing features, like iconic user 
  292. interfaces, that grew up in prototyping environments and which depend 
  293. on experimentation and tuning for good human factors.  This kind of tuning
  294. is far easier in prototyping languages like Smalltalk-80, because machine
  295. resources can be spent lavishly on pervasive productivity aids like automatic
  296. garbage collection, and because the tools are tightly coupled to the system
  297. being constructed.
  298. .pp
  299. However the C/Unix community has historically favored a non-integrated 
  300. approach that keeps the product separate from the tools, and they commonly 
  301. exploit special purpose languages to amplify C's basic capabilities; 
  302. i.e. \fIyacc\fP for building parsers, \fIlex\fP for building lexical
  303. analyzers, \fItroff\fP for formating documents, \fImake\fP for controlling
  304. compilations, \fIadb\fP or \fIdbx\fP for debugging, and many others\**.
  305. So why not treat Smalltalk-80 as a special purpose tool for rapid 
  306. prototyping and ultimately translate the prototypes into C for
  307. production? This could eliminate the cradle to grave committment problem
  308. that has hindered Smalltalk's acceptance to date, and would integrate 
  309. the strengths of the two approaches into a comprehensive hybrid software 
  310. development environment.
  311. .(f
  312. \** Unix Programmers Manual. In particular see \fILex - A Lexical Analyzer 
  313. Generator\fP, and \fIYacc - Yet Another Compiler Compiler\fP. Also see \fILR
  314. Parsing\fP, Aho and Johnson, Computing Surveys, June, 1974.
  315. .)f
  316. .pp
  317. This article describes a tool-assisted process for translating Smalltalk-80
  318. applications into C language. The routine parts of the process are handled
  319. by a translation tool, \fIproducer\fP, which translates Smalltalk-80 code into
  320. Objective-C, an object-oriented extention to C language.  Obviously, it is
  321. not realistic to expect any tool to turn arbitrary half-baked prototypes
  322. into polished software products automatically. Nor can static analysis make
  323. perfectly accurate predictions about a program's dynamic behavior, such
  324. as the specific type a polymorphic variable will hold at run time or when
  325. it is safe to release storage that may be multiply referenced. This 
  326. information is not available in the text of a Smalltalk program and 
  327. deriving it by static analysis is a truly hard (NP-complete) problem. 
  328. This work sidesteps these problems by keeping the programmer involved in
  329. the translation process.
  330. .pp
  331. Translating code between languages as different as these is like designing
  332. a bridge. Although bridge builders often use generic tools and components,
  333. each bridge is custom designed to fit within a larger system of expressways,
  334. access roads, and approach ramps.  No part is designed in isolation, but in 
  335. combination to reduce the overall cost of the project.  Producer is not a
  336. bridge, but a component from which bridges can be assembled.  It need not
  337. solve the general problem of translating arbitrary Smalltalk-80 program into
  338. C with guaranteed reliablity, since the programmer can help by changing the
  339. source and target environments, by guiding the translation, or even by 
  340. repairing translation errors by hand. 
  341.  
  342. .H "Background"
  343. This work was made feasible by several other PPI projects, all directed at
  344. the same goal; adapting concepts and tools that have been proven in the
  345. prototyping community for use in production programming.  The foundation
  346. is Objective-C language, which is implemented by a compiler that translates
  347. object-oriented constructs of Smalltalk-80 into expressions that can compiled
  348. by any C compiler.  The same language is also available in \fIVici\fP, an 
  349. interpreter that allows classes and ordinary C code to be developed, tested,
  350. and changed interactively by eliminating the usual edit, compile, link, and
  351. test cycle.
  352. .(f
  353. \** \fIObject-oriented Programming, An Evolutionary Approach\fP, Brad Cox,
  354. Addison Wesley, 1986.
  355. .)f
  356. .pp
  357. Both products make object-oriented programming available to production
  358. programmers. This make it possible for them to cooperate in building and
  359. reusing large libaries of pretested, documented classes that PPI 
  360. calls \fISoftware-ICs\fP to dramatize important parallels between 
  361. object-oriented programming and the invention of the integrated circuit
  362. chip, two technologies for packaging the efforts of suppliers for reuse
  363. by consumers. This provides the crucial missing element that has until 
  364. now prevented software developers from obtaining the explosive growth
  365. in productivity that hardware developers achieve routinely.
  366. .pp
  367. Several such libraries have been implemented.  Classes similar to Smalltalk's
  368. lower-level classes (Arrays, Collections, etc) have long been available\**, 
  369. .(f
  370. \** \fISoftware-IC Specification Sheets\fP, Objective-C Programmers 
  371. Reference Manual; PPI.
  372. .)f
  373. and a compatible library of user interface Software-ICs has recently been 
  374. developed in a form that is portable across the windowing environments of 
  375. most engineering workstations\**.
  376. .(f
  377. \** \fIObject-oriented Programming and Iconic User Interfaces\fP, 
  378. Bill Hunt (Hewlett Packard) and Brad Cox (PPI), Byte Magazine, August 1986.
  379. .)f
  380. Other projects\** have developed additional features of the Smalltalk 
  381. substrate, including an (optional) automatic garbage collector.
  382. .(f
  383. \** Unpublished; Frank Parish (Hewlett Packard) and Alan Watt (PPI).
  384. .)f
  385. .pp
  386. These libraries provide the substrate needed to build an eventual Unix-based
  387. environment that has many Smalltalk-like features such as an interactive
  388. browser for developing, describing, learning about, and using large 
  389. collections of ordinary C code and/or Software-ICs.  Although this will 
  390. make programming with C and/or Objective-C more productive, it is by design
  391. an environment for production programming and will not eliminate the need
  392. for Smalltalk-80 as a specialized prototyping environment.
  393.  
  394. .H "Prototyping versus Production Programming"
  395. When a line of Smalltalk-80 code works correctly, it has successfully met
  396. several layers of requirements imposed by the Smalltalk-80 language, its
  397. run-time environment, and the programmer who wrote it. In transforming it
  398. into Objective-C code, it must meet similar requirements of the target
  399. language, environment, and programmer.  These requirement layers amount
  400. to progressively higher hurdles over which the code must be carried:
  401. .np
  402. Syntactic: The first hurdle involves converting syntactically valid 
  403. Smalltalk-80 statements to syntactically valid Objective-C statements.
  404. This can be done with simple tools that are concerned only the syntax of
  405. the two programming \fIlanguages\fP.
  406. .np
  407. Semantic: The second hurdle involves preserving the meaning of the code,
  408. when executed in the Smalltalk-80 environment, when it has been transformed
  409. for execution in the Objective-C environment. This requires knowledge of
  410. the two \fIenvironments\fP.
  411. .np
  412. Intentional: This is a coined term that signifies transforming code that
  413. reflects the intentions of the prototype builder to meet the intentions of
  414. one building a system for production.  This requires knowledge of the
  415. intentions of the \fIprogrammers\fP themselves, or more practically,
  416. their direct involvement in one or more stages of the translation.
  417. .pp
  418. Since Objective-C's object-oriented capabilities were modeled directly 
  419. after Smalltalk's, message expressions can be translated one for one
  420. into Objective-C messages.  However this is of so little practical interest
  421. that it has never been attempted.  After passing each of the Smalltalk
  422. classes through such a translator, implementing the entire Smalltalk 
  423. virtual machine, and installing an automatic garbage collector, the 
  424. translated code would have the vices of both languages and the virtues
  425. of neither.  It would run no faster and it would be just as incompatible
  426. with other Unix tools.  To be of practical interest, the translation 
  427. process must also provide a way of providing correctness at each one of
  428. the other levels; syntactic, semantic, and intentional. This is hard to
  429. do automatically, but relatively easy if the programmer is involved 
  430. in the translation.
  431. .pp
  432. For example, a Smalltalk-80 prototype might conceivably compose statements
  433. as data and compile them for execution on the fly. Although Objective-C is
  434. designed primarily as a language to be compiled in advance of program
  435. execution, several options are available for translating these prototypes. 
  436. The programmer might choose to incorporate \fIVici\fP into the target system,
  437. as this would reduce labor costs at the source side. Or he might decide
  438. to modify the prototype to avoid this feature to provide better execution 
  439. speed on the target side.  Similarly, Smalltalk-80 implements low-level 
  440. types like points (coordinates) as dynamically-bound objects, and this 
  441. allows higher level code to be independent of whether points are represented
  442. as integers or floating point numbers. Objective-C's user interface library 
  443. removes this freedom in favor of greater machine efficiency. Should a
  444. Smalltalk program rely on polymorphic points, its programmer could choose 
  445. between developing a different user interface library that does use
  446. polymorphic points, changing the prototype to avoid the problem, or
  447. accepting a certain proportion of errors in the translation to be repaired
  448. by hand. No translation is impossible; some just cost more than others.
  449.  
  450. .H "Producer"
  451. The automatic part of a translation involves a tool named `producer'.  Producer
  452. is basically a Smalltalk-80 compiler that generates Objective-C code, but it
  453. differs from most compilers in that it can also accept additional information 
  454. to guide how code will be generated. If this information is not provided,
  455. producer translates Smalltalk-80 statements into Objective-C code in a
  456. straightforward, non-rigorous manner. For example, it will translate each
  457. Smalltalk message expression to a syntactically equivalent Objective-C
  458. expression, but it translates literal constants into primitive C types and
  459. does nothing special to ensure that the code generated from Smalltalk
  460. block expressions is syntactically legal.
  461. .pp
  462. Producer is implemented in Objective-C and other Unix tools.  Its lexical
  463. analyzer, written in \fIlex\fP, composes characters into tokens and delivers 
  464. them to the parser, written in \fIyacc\fP. The parser recognizes syntactic 
  465. components of the Smalltalk-80 language and executes Objective-C statements 
  466. that build a syntax tree bottom-up as instances of syntactic classes like 
  467. Method, Message, and Identifier. Some of these classes eliminate minor 
  468. syntactic incompatibilities by rewriting the tree. For example, the Expr
  469. (expression) class eliminates cascaded message expressions by adding temporary
  470. variables to the nearest enclosing scope and builds the tree as a sequence 
  471. of simple message expressions.
  472. .pp
  473. As a refinement, the lexer accumulates every token in a list that can be
  474. printed just before the code generation pass as an Objective-C comment.
  475. This preserves the original Smalltalk statements and comments in the 
  476. generated code.  Code generation begins when the grammar recognizes a 
  477. method or class declaration and sends the top of the syntax tree (an
  478. instance of Method or Class) the message, \fIgen\fP. The method class 
  479. implements this message by first requesting its subnodes to determine 
  480. their types, a recursive process that involves rule processing and type
  481. inferencing.  Then it begins code generation by generating tokens that
  482. Objective-C will recognize as a method declaration and requests its
  483. subnodes to do likewise.
  484. .pp
  485. In principle, translation rules could be attached to any syntactic class,
  486. but currently only the Method, Message, and Identifier classes provide the
  487. necessary hooks. Rules are typically provided in separate files that are 
  488. read before the source to be translated and are parsed by special grammar
  489. productions.  Identifier rules declare the type of specific identifiers and
  490. can optionally assign a new spelling for each identifier in the generated
  491. code.  Most often, declarations are provided only for instance variables 
  492. and method arguments since these generally provide sufficient information 
  493. that types of other variables (method and block local variables) can be
  494. inferred from how they are used.
  495. .pp
  496. The Message class provides a more elaborate kind of hook that allows more
  497. than one translation to be associated with each selector (a similar hook
  498. exists in the Method class).  The specific translation for such messages
  499. is chosen according to typing information that can be derived from several 
  500. sources. The type of literal constants is derived automatically, and types 
  501. of variables are determined by declarative rules provided by the programmer 
  502. and also by type inferencing rules that are built into producer. The argument
  503. or receiver of one message is often another message expression, whose type
  504. depends on the type of its arguments, and so on recursively.  Currently,
  505. translations for messages are chosen according to the selector and the
  506. type of the message's receiver and arguments (forward reasoning), but this 
  507. may be extended to also consider how the result of the translated message 
  508. is used (backward reasoning).
  509. .pp
  510. Blocks are translated via the usual message translation rules, triggered 
  511. by arguments of type BLOCK. While many blocks can be translated as
  512. as C conditional statements and expressions (if, for, while, etc),
  513. elaborate blocks cannot be translated in this way.  If experience
  514. demonstrates the need, more ambitious translations can be added,
  515. such as rewriting block bodies as C function bodies.
  516.  
  517. .H "Results"
  518. The current implementation of producer consists of 1804 lines of Objective-C
  519. code, 223 of which are also processed by yacc and 105 by lex. Only three
  520. man-weeks have been invested, two in developing producer and producing
  521. the results shown here and the other in writing this paper. To date,
  522. translations have been verified by desk checking, but it should be possible
  523. to show translated applications in operation by the time this paper is
  524. presented.
  525. .pp
  526. The group that developed Smalltalk-80 has produced a video tape that Xerox
  527. uses to promote sales of Smalltalk systems. The tape concludes with a 
  528. animation of three shapes bouncing in a rectangular enclosure; a circle, a
  529. rotating star, and a square that shows the area near the cursor. The tape
  530. was filmed on a Dorado, a relatively powerful computer, but the same program
  531. is also available on less expensive machines like the Tektronix Artificial 
  532. Intelligence Workstation, which is based on the same Motorola 68010 chip
  533. as the Sun workstations used in most of our work. This program was chosen
  534. to demonstrate the translation process in action.
  535. .pp
  536. The animation application involves 236 lines of Smalltalk code. Its source
  537. environment is the standard Smalltalk-80 environment, and the goal is to
  538. translate it to run in a target environment that is defined by the 
  539. Objective-C user interface library.  This environment involves three 
  540. layers of abstraction:
  541. .np
  542. The substrate layer includes the primitive data types of the C compiler,
  543. Unix, and the proprietary windowing environments of diverse workstation
  544. vendors, and is therefore not part of the library. The library confines
  545. itself to building user interfaces to run in virtual terminals provided
  546. by the windowing environment.
  547. .np
  548. The DisplayObjects level duplicates the functionality of the Smalltalk 
  549. graphics environment insofar as this has been described publically\**.
  550. It provides a Form class whose instances hold rectangular raster images 
  551. in memory, a DisplayScreen class (a subclass of Form) whose instances
  552. provide an object-oriented interface to a virtual terminal, and a number
  553. of specialized subclasses like InfiniteForm, OpaqueForm, Cursor, and Sensor.
  554. The classes and methods in this library are essentially identical to 
  555. Smalltalk's, but they assume that objects below the level of class Rectangle
  556. are primitive types of the substrate; e.g. Points, Numbers, Booleans, and 
  557. so forth.
  558. .(f
  559. \** Goldberg and Robson's \fISmalltalk-80: The language and its
  560. implementation\fP
  561. .)f
  562. .np
  563. The UserInterface level is similar to, but does not duplicate, the Smalltalk
  564. Interface-Framework classes that implement the model/view/controller (MVC) user 
  565. interface paradigm. This level of the library is not compatible, partially
  566. because MVC seems unnecessarily complicated, but primarily to avoid any
  567. appearance of violating Xerox copyright protection on concepts that are
  568. documented only in Smalltalk-80 sources. Unless this restriction can be
  569. lifted, the only recourse may be to code prototypes to use a new Smalltalk
  570. library written to parallel the Objective-C library.
  571. .pp
  572. The DisplayObjects level also defines a statically typed implementation 
  573. of the Point (coordinate) class as a collection of C macros and functions:
  574. .(C
  575. typedef struct { short x, y; } PT;\**    // aPoint
  576. .)C
  577. This trades the advantages of polymorphic points to gain machine efficiency 
  578. and compatibility with other tools in the target environment; particularly 
  579. vendor-supplied windowing environments. And managing low level objects like
  580. points by value instead of by reference reduces the need for automatic
  581. garbage collection significantly.
  582. .(f
  583. \** Since many C compilers implement structure assignment inefficiently,
  584. the library coerces this type such that points are passed to and returned
  585. from functions as integers rather than as structures. This is why the x
  586. portion of aPoint is accessed as X(aPoint) rather than aPoint.x.
  587. .)f
  588. .pp
  589. The translation for this application involves 796 lines of rules, 735 of
  590. which are generic rules that describe low-level Smalltalk objects (Booleans,
  591. Numbers, etc) and 61 of which are application-specific rules that describe
  592. types in the animation application. The following is a typical translation:
  593. .(C
  594. // MovingNode subclass: #BounceInBoxNode
  595. //    instanceVariableNames: ''
  596. //    classVariableNames: ''
  597. //    poolDictionaries: ''
  598. //    category: 'Graphics-Animation'!
  599.  
  600. #include "st80.h"
  601. = BounceInBoxNode:MovingNode CATEGORIES() { }
  602.  
  603. // !BounceInBoxNode methodsFor: 'display'!
  604. // displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle rule: 
  605. //    ruleInteger mask: aForm
  606. //    | relLoc |
  607. //    super displayOn: destForm at: aDisplayPoint clippingBox: clipRectangle 
  608. //        rule: ruleInteger mask: aForm.
  609. //    relLoc \(<- location + clipRectangle origin.
  610. //    (velocity x < 0 and: [relLoc x < clipRectangle left])
  611. //        ifTrue: [velocity \(<- velocity*(-1@1)].
  612. //    (velocity x > 0 and: [(relLoc x+contents width) > clipRectangle right])
  613. //        ifTrue: [velocity \(<- velocity*(-1@1)].
  614. //    (velocity y < 0 and: [relLoc y < clipRectangle top])
  615. //        ifTrue: [velocity \(<- velocity*(1@-1)].
  616. //    (velocity y > 0 and: [(relLoc y+contents height) > clipRectangle bottom])
  617. //        ifTrue: [velocity \(<- velocity*(1@-1)].
  618. - displayOn:destForm at:(PT)aDisplayPoint clipBy:clipRectangle rule:(int)ruleInteger mask:aForm {
  619.     PT relLoc;
  620.     [super displayOn:destForm at:aDisplayPoint clipBy:clipRectangle rule:ruleInteger mask:aForm];
  621.     relLoc = ptPlus(location, [clipRectangle origin]);
  622.     if (X(velocity) < 0 && X(relLoc) < [clipRectangle left])
  623.             velocity = ptTimes(velocity, pt(-1,1));
  624.     if (X(velocity) > 0 && X(relLoc) + [contents width] > [clipRectangle right])
  625.             velocity = ptTimes(velocity, pt(-1,1));
  626.     if (Y(velocity) < 0 && Y(relLoc) < [clipRectangle top])
  627.             velocity = ptTimes(velocity, pt(1,-1));
  628.     if (Y(velocity) > 0 && Y(relLoc) + [contents height] > [clipRectangle bottom])
  629.             velocity = ptTimes(velocity, pt(1,-1));
  630.     return self;
  631. }
  632. .)C
  633. .pp
  634. The original Smalltalk statements are shown in the comments preceeding each
  635. block of translated code. The translation of the first few lines in the method
  636. were influenced primarily by rules from a file of application-specific 
  637. information, of which three are shown here:
  638. .(C
  639. { # location (PT) location }
  640. { # velocity (PT) velocity }
  641. { (id)displayOn:(id) at:(PT) clippingBox:(id) rule:(int) mask:(id) #
  642.     (id) [displayOn:%1 at:(PT)%2 clipBy:%3 rule:(int)%4 mask:%5] }
  643. .)C
  644. The two instance variables, location and velocity, were inherited from
  645. another application-specific class, PositionNode. The first two rules
  646. declare that they are both of type PT (Point) and should be translated 
  647. without change in spelling. The third rule specifies that methods and 
  648. messages whose selector is displayOn:at:clippingBox:rule:mask: and whose
  649. receiver and arguments type id, id, PT, id, int and id respectively,
  650. should be translated into a message with the modified selector
  651. displayOn:at:clipBy:rule:mask: and with argument types and positions 
  652. as denoted in the right hand part of the rule. No declaration was provided
  653. for the local variable relLoc, so its type was inferred from the type of 
  654. the first statement that assigns it a value, namely
  655. .(C
  656. relLoc \(<- location + clipRectangle origin.
  657. .)C
  658. The translation of this statement was determined by two rules from a
  659. different file of generic rules about low-level Smalltalk-80 objects.
  660. .(C
  661. { # (PT) [origin] }
  662. { (PT)+ (PT) # (PT)'ptPlus(%0, %1)' }
  663. .)C
  664. The first rule denotes that the origin message, applied to an receiver
  665. of any type, returns a Point, and the second that the + message sent to
  666. an receiver of type Point with an argument of the same type translates 
  667. as a call on the C function ptPlus which returns a value of type PT.
  668. .pp
  669. Currently, producer does nothing special for blocks, aside from giving them
  670. a unique type (BLOCK) that can be tested by ordinary message rules. For
  671. example, the `if' statements were produced by such a rule:
  672. .(C
  673. { ifTrue:(BLOCK) # (STMT)'if (%0) %1' }
  674. .)C
  675.  
  676. .H "Conclusions"
  677. The primary conclusion that can be drawn from the results to date is that
  678. small Smalltalk applications that do not lean heavily on complex features
  679. of the Smalltalk environment can be translated to Objective-C with remarkably
  680. little trouble. Only two man-weeks sufficed to build a reasonably effective
  681. translation tool and a generic collection of rules that could translate a
  682. 263 line Smalltalk program into Objective-C with only 61 lines of application
  683. specific information.  Once the application is operational, it may be
  684. possible to draw additional conclusions about the overall merit of the
  685. translation concept, for example by comparing the animation example's 
  686. performance before and after translation.
  687. .pp
  688. This work has also identified several limitations in how the translation
  689. program is currently implemented, but it is too early to know whether they
  690. are serious enough to warrant fixing. For example, the scheme used for
  691. handling Smalltalk-80 block expressions works primarily because of
  692. serendipity, not because Smalltalk blocks are equivalent to any construct
  693. that C provides. Experience may prove that Smalltalk-80 programmers
  694. usually use blocks just as C programmers use simple conditional statements,
  695. in which case there would be little need for anything more elaborate,
  696. particularly since misses are automatically flagged as syntax errors when 
  697. the generated code is compiled and could be repaired by hand. A number of
  698. more elaborate schemes are also available, up to and including a direct
  699. implementation of Smalltalk's scheme, and it is too soon to say which of
  700. these will prove sufficient.
  701. .pp
  702. Several limitations have been identified in how rules are currently processed.
  703. The fundamental restriction is that rules can only define data which is
  704. interpreted by hard-coded logic, so it is not possible to write rules that
  705. recognize and translate entities larger than an individual message expression.
  706. For example, the current scheme could not eliminate wasteful Smalltalk idioms
  707. like `Form under' by replacing the message with a constant, because this
  708. would involve examining not only the type of the message's receiver, but
  709. also its name. For much the same reason, it could not eliminate the 
  710. unnecessary function call in the body of the first `if' statement by
  711. translating it to:
  712. .(C
  713. X(velocity) *= -1;\**
  714. .)C
  715. .(f
  716. \** X() and Y() are C macros, not functions. They are L-values and can be
  717. used as the target of assignment statements.
  718. .)f
  719. If this restriction proves too limiting in practice, it could be relieved
  720. by incorporating a general-purpose rule interpreter such as Prolog.
  721. .pp
  722. There are a number of smaller problems that should certainly be repaired.
  723. Currently, rules have global scope and they should instead be attached to 
  724. specific classes, methods, or blocks to provide finer control over how 
  725. identifier spellings and types are assigned. Identifier rules should be 
  726. organized into a type hierarchy, and types should be compared by something 
  727. more sophisticated than mere equality of their names. These enhancements 
  728. would increase the modularity and generality of the translation rules, but 
  729. would not influence the range of translations that producer can perform.
  730. .pp
  731. The final result is that we have received the encouragement that we need
  732. to pursue this idea further. Translation does appear to be a viable way
  733. of integrating the best of two worlds into a comprehensive hybrid 
  734. programming environment that spans a much larger segment of the 
  735. software development life-spiral than ever before.
  736. \Rogue\Monster\
  737. else
  738.   echo "will not over write ./producer.me"
  739. fi
  740. echo "Finished archive 2 of 5"
  741. exit
  742. ----
  743. Dieter H. Zebbedies ('dee-ter  ayech  'zeb-ed-eez)
  744.  Zebb-Hoff Mach. Tool's Automated Manufacturing Project Cleveland, OH
  745.  (USnail): 9535 Clinton Rd, Cleveland, OH 44144 (+216 631 6100) (+216 741-5994)
  746.  (UUCP): ...{decvax,sun,cbosgd}!cwruecmp!zhmti!dieter
  747.  (CSNET/ARPA/BITNET): dieter@CWRU.EDU
  748.