home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume13 / little-st2 / part04 < prev    next >
Encoding:
Internet Message Format  |  1988-01-30  |  46.9 KB

  1. Subject:  v13i056:  New release of little smalltalk, Part04/05
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Tim Budd <budd@MIST.CS.ORST.EDU>
  7. Posting-number: Volume 13, Issue 56
  8. Archive-name: little-st2/part04
  9.  
  10. #!/bin/sh
  11. #
  12. # This is version 2.02 of Little Smalltalk, distributed in five parts.
  13. # This version is dated 12/25/87
  14. # Several bugs and many features and improvements have been made since the
  15. # first posting to comp.src.unix.  See the file ``todo'' for a partial list.
  16. # Comments, bug reports, and the like should be submitted to:
  17. #     Tim Budd
  18. #     Smalltalk Distribution
  19. #     Department of Computer Science
  20. #     Oregon State University
  21. #     Corvallis, Oregon
  22. #     97330
  23. #     budd@cs.orst.edu
  24. #     {hp-pcd, tektronix}!orstcs!budd
  25. #
  26. echo 'Start of small.v2, part 04 of 05:'
  27. echo 'x - at.ms'
  28. sed 's/^X//' > at.ms << '/'
  29. X.LP
  30. X(note: this is the first of a series of essays descriging how various 
  31. Xfeatures of the Little Smalltalk bytecodes work).
  32. X.SH
  33. XWhere It's At
  34. X.PP
  35. XThis short note explains how the messages \fBat:\fP, \fBat:put:\fP, and their 
  36. Xrelatives are defined and used in collections.  We start by discussing the 
  37. Xsimplest form of collections, arrays and strings.
  38. X.PP
  39. XThe message \fBat:\fP is not defined anywhere in class \fBArray\fP or any of
  40. Xits subclasses.  Instead, this message is inherited from 
  41. Xclass \fBCollection\fP, which defines it using the following method:
  42. X.DS I
  43. X\fBat:\fP index
  44. X    \(ua self at: index
  45. X        ifAbsent: [ smalltalk error: 'index to at: illegal' ]
  46. X.DE
  47. X.PP
  48. XThe functioning of the message \fBerror:\fP is the topic of another essay;
  49. Xit is sufficient for our purposes to note only that this message prints out
  50. Xthe error string and returns nil.  By redefining \fBat:\fP in this fashion,
  51. Xthe subclasses of \fBCollection\fP need not be concerned about how to deal
  52. Xwith errors in cases where no error recovery action has been specified.
  53. X.PP
  54. XFor an array, an index is out of bounds if it is either less than 1 or greater
  55. Xthan the size of the array.  This is tested by a method in class \fBArray\fP:
  56. X.DS I
  57. X\fBincludesKey:\fP index
  58. X    ^ index between: 1 and: self size
  59. X.DE
  60. X.PP
  61. XThe message \fBsize\fP is defined in class \fBArray\fP in terms of the
  62. Xmessage \fBbasicSize\fP
  63. X.DS I
  64. X\fBsize\fP
  65. X    ^ self basicSize
  66. X.DE
  67. X.PP
  68. XThe message \fBbasicSize\fP (as well as \fBbasicAt:\fP, discussed below) 
  69. Xis inherited from class 
  70. X\fBObject\fP.  It can be used on any object; on non-arrays it returns
  71. Xthe number of instance variables for the object.  The messages \fBbasicSize\fP 
  72. Xand \fBbasicAt:put:\fP can be used by system
  73. Xclasses, for example debuggers, to access instance variables in an object 
  74. Xwithout having explicit access to the instance variables.  One must be 
  75. Xcareful, however,
  76. X\fBbasicAt:\fP produces a system error, and not a Smalltalk error message,
  77. Xif it is given an index value that is out of range.
  78. X.PP
  79. XUsing \fBincludesKey:\fP for a test, a value is only accessed if the index
  80. Xis legal.  The following method appears in class \fBArray\fP:
  81. X.DS I
  82. X\fBat:\fP index \fBifAbsent:\fP exceptionBlock
  83. X    ^ (self includesKey: index)
  84. X        ifTrue: [ self basicAt: index ]
  85. X        ifFalse: [ exceptionBlock value ]
  86. X.DE
  87. X.PP
  88. XA subclass of \fBArray\fP is the class \fBByteArray\fP.  A byte array is a form
  89. Xof array in which the elements can only take on values from zero to 255, or
  90. Xto put it another way, values that can be stored in one byte.
  91. XOn most 16 bit machines, we can store two such bytes in the space it takes
  92. Xto store one object pointer.  Thus, the message \fBsize\fP is redefined
  93. Xin class \fBByteArray\fP as follows:
  94. X.DS I
  95. X\fBsize\fP
  96. X    \(ua self basicSize * 2
  97. X.DE
  98. X.LP
  99. XNote that this implies that byte arrays always have an even number of
  100. Xelements.  Next the message \fBbasicAt:\fP is redefined to use a byte,
  101. Xinstead of object, form of index.  This is accomplished using a primitive
  102. Xmethod, (the message \fBbasicAt:\fP is handled in a similar fashion in
  103. Xclass \fBObject\fP, only using a different primitive).
  104. X.DS I
  105. X\fBbasicAt:\fP index
  106. X    \(ua <26 self index>
  107. X.DE
  108. X.PP
  109. XLike a byte array, a string can also store two byte values in the space
  110. Xit takes to store a single object pointer.  Unlike a byte array, however,
  111. Xa string can be any length, not just an even length.  Therefore the message
  112. X\fBsize\fP is redefned in class \fBString\fP, a subclass of \fBByteArray\fP.
  113. X.DS I
  114. X\fBsize\fP
  115. X    \(ua <14 self>
  116. X.DE
  117. X.PP
  118. XAnother difference between a string and a byte array is that the value
  119. Xreturned by a string must be a character, not an integer.  Therefore
  120. X\fBbasicAt:\fP must also be redefined.  By using the message \fBbasicAt:\fP
  121. Xdefined in \fBByteArray\fP, (the superclass of String, and therefore accessible
  122. Xvia the pseudo variable \fBsuper\fP) the method can obtain the integer value 
  123. Xof the appropriate character.  This value is then used to create a new
  124. Xinstance of class \fBChar\fP:
  125. X.DS I
  126. X\fBbasicAt:\fP index
  127. X    \(ua Char new; value: (super basicAt: index)
  128. X.DE
  129. X.PP
  130. XA value is placed into an array using the message \fPat:put:\fP.  As with 
  131. X\fBat:\fP, a value should only be placed if the index represents a legal
  132. Xsubscript.  This is checked in the following method:
  133. X.DS I
  134. X\fBat:\fP index \fBput:\fP value
  135. X    (self includesKey: index)
  136. X        ifTrue: [ self basicAt: index put: value ]
  137. X        ifFalse: [ smalltalk error: 
  138. X            'illegal index to at:put: for array' ]
  139. X.DE
  140. X.PP
  141. XAs was the case with \fBbasicAt:\fP, one version of \fBbasicAt:put:\fP,
  142. Xto be used by arrays of objects, is defined as part of class \fBObject\fP.
  143. XA different version is found in class \fBByteArray\fP.  Finally a third 
  144. Xversion, which first checks to see if the argument is a Character, is found
  145. Xin class \fBString\fP.
  146. X.DS I
  147. X\fBat:\fP index \fBput:\fP aValue
  148. X    (aValue isMemberOf: Char)
  149. X        ifTrue: [ super basicAt: index put: aValue asciiValue ]
  150. X        ifFalse: [ smalltalk error:
  151. X            'cannot put non Char into string' ]
  152. X.DE
  153. X.SH
  154. XExercises
  155. X.IP 1.
  156. XDescribe the sequence of messages used to respond to the following:
  157. X.DS B
  158. Xx \(<- #(1 2 3) at: 2
  159. X.DE
  160. X.IP 2.
  161. XDescribe how the execution of the above expression could be speeded up by
  162. Xadding new methods.  Note if your methods are specific to arrays of objects,
  163. Xarrays of bytes, or strings.
  164. /
  165. echo 'x - general.ms'
  166. sed 's/^X//' > general.ms << '/'
  167. X.\" information on Little Smalltalk, version 2, beta release
  168. X.SH
  169. XGeneral Overview
  170. X.PP
  171. XFirst, the obvious facts.  This is not Smalltalk-80, nor even Smalltalk-V.
  172. XThis is the second version of the Little Smalltalk system, the first version
  173. Xof which is described in the book recently published by Addison-Wesley*.
  174. X.FS
  175. X* \fIA Little Smalltalk\fP, by Timothy A. Budd.  Published by Addison
  176. XWesley, 1987.  In better bookshops everywhere.
  177. X.FE
  178. XVersion two is smaller and faster; does more in Smalltalk, less in C; and is
  179. Xdesigned to be more portable to a wider variety of machines (we are working
  180. Xon versions now for various PCs).  
  181. X.PP
  182. XMy attitude towards the language has been
  183. Xrather cavalier; what I liked I kept and what I didn't like I tossed out.
  184. XThis is explained in more detail in my book and in the end of this note.
  185. XAs a consequence, individuals familiar with ST-80 or Smalltalk-V will be struck 
  186. Xby how much they are missing, and I make no apologies for this.  On the
  187. Xother hand, you don't find Smalltalk-V posted to comp.source.unix.  
  188. XAmong the features
  189. Xyou won't find here are metaclasses, class methods, windows, graphics 
  190. Xsupport, and more.
  191. X.PP
  192. XWhat you will find is a small language that does give you the flavor of
  193. Xobject oriented programming at very little cost.  We are working to improve
  194. Xthe system, and hope to distribute new versions as we develop them, 
  195. Xas well as porting it to a wide range of machines.
  196. XIf you find (and preferably, fix!) bugs let us know.
  197. XIf you make nice additions let us know.
  198. XIf you want to make complements let us know.
  199. XIf you want to make complaints let us know.
  200. XIf you want support you just might be out of luck.
  201. X.PP
  202. XThis software is entirely public domain.  You are encouraged to give it
  203. Xto as many friends as you may have.  As a courtesy, I would appreciate it
  204. Xif you left my name on the code as the author, but I make no other claims
  205. Xto it (I also, of course, disavow any liability for any bizarre things you
  206. Xmay choose to do with it).  Enjoy.
  207. X.SH
  208. XBuilding the System
  209. X.PP
  210. XThe first step in building the system is to unpack the sources.
  211. XThe fact that you are reading this means you have probably already figured
  212. Xout how to do this.
  213. X.PP
  214. XThere are various different types of files sent with the distribution.
  215. XFiles ending in .c and .h are C sources, for both the parser and the bytecode
  216. Xinterpreter.  Files ending in .ms are manuscripts, in troff format using
  217. Xthe ms macro package (this file is a good example).  Files ending in .st
  218. Xare smalltalk sources, compiled by the parser to make the initial object
  219. Ximage.  Finally, there are a few small files that don't fall into any
  220. Xcategory, BUGS for listing notable bugs, the make file, and so on.
  221. X.PP
  222. XThe next step is to tailor the system to the type of enviornment it will be
  223. Xrun in.
  224. XFor most users, this should mean only changing at most three lines in the
  225. Xfile env.h.  These three lines are near the front of the file and are
  226. Xclearly marked.  Two are hard paths; for the default initial object image
  227. Xand for a temporary file to be used when editing.  The third line is a
  228. X``meta-define'' which indicates the type of machine and/or operating system
  229. Xto be used.  You should examine the rest of the file to see the variety of
  230. Xsystems supported.  If you are unable to find anything appropriate, you will
  231. Xhave to look in the document install.ms for further instructions.  In this
  232. Xlatter case, if you are sucessful in porting the software to a new machine,
  233. XI would be pleased if you could let me know the nature of the changes
  234. Xrequired.
  235. X.PP
  236. XOnce you have tailored the system, there are then
  237. Xthree steps involving in building the system; making the parser
  238. X(the component used to generate the initial object image), making the
  239. Xbytecode interpreter, and making the object image.  Typing \fImake\fP, with
  240. Xno arguments, will do all three.  For more detailed instructions on making
  241. Xthe system consult install.ms.
  242. X.PP
  243. XOnce you have sucessfully created the parser, the bytecode compiler, and
  244. Xan object image, type 
  245. X.DS I
  246. Xst
  247. X.DE
  248. X.LP
  249. Xto run the system.
  250. XNow would be a very good time to go read explore.ms, which would tell you
  251. Xmore how to find your way around.
  252. X.SH
  253. XChanges from Little Smalltalk version one
  254. X.PP
  255. XThe following changes have been made from version one to version two:
  256. X.IP \(bu
  257. XThe user interface is slightly different.  This is most apparent in the way
  258. Xnew classes are added (see explore.ms), and in the fact that expressions will
  259. Xnot be printed unless you explicitly request printing, and in the fact that
  260. Xnew global variables cannot be created at the command level merely by
  261. Xassignment.
  262. X.IP \(bu
  263. XMuch (very much) more of the system is now written in Smalltalk, rather
  264. Xthan C.  This allows the user to see, and modify it if they wish.
  265. XThis also means that the virtual machine is now much smaller.
  266. X.IP \(bu
  267. XThe pseudo variable selfProcess is no longer supported.
  268. XThe variables true, false and nil are now treated as global variables, not
  269. Xpseudo variables (see below).
  270. XThere are plans for adding processes to version two, but they have not
  271. Xbeen formalized yet.
  272. X.IP \(bu
  273. XGlobal variables are now supported; in fact classes are now simply global
  274. Xvariables, as are the variables true, false, smalltalk and nil.
  275. XThe global variable globalNames contains the dictionary of all currently
  276. Xknown global variables and their values.
  277. X(Pool variables are still not supported).
  278. X.IP \(bu
  279. XNumbers are a little more robust.  If integer operations overflow, they are
  280. Xautomatically converted into floating point numbers.  This is under control
  281. Xof Smalltalk code, so if I (or, preferably, somebody else) ever get around
  282. Xto implementing infinite precision numbers, they can easily be added in.
  283. X.IP \(bu
  284. XThe internal bytecodes are slightly different.  In particular, the bytecode
  285. Xrepresenting ``send to super'' has been eliminated, and a bytecode representing
  286. X``do a primitive'' has been added.
  287. X.IP \(bu
  288. XThe internal representation of objects is different.  Instead of the
  289. X``super-object'' chain, objects are now created big enough to hold all the
  290. Xinstance variables for all their superclasses.  (This is the way it is done
  291. Xin Smalltalk-80, and, to the best of my knowledge, in Smalltalk-V).
  292. X.IP \(bu
  293. XThe Collection hierarchy has been rearranged.  The rational for this change
  294. Xis explained in more detail in another essay.
  295. X(possibly not written yet).
  296. X.IP \(bu
  297. XSome methods, most notably the error message methods, have been moved out
  298. Xof class Object and into class Smalltalk.
  299. X.IP \(bu
  300. XThe syntax for primitives is different; the keyword \fBprimitive\fP has been
  301. Xeliminated, and named primitives are now gone as well.
  302. XFewer actions are performed by primitives, having been
  303. Xreplaced by Smalltalk methods.
  304. X.IP \(bu
  305. XCommand line options, such as the fast load feature, have been eliminated.
  306. XHowever, since version two reads in a binary object image, not a textual
  307. Xfile, loading should be considerably faster.
  308. X.SH
  309. XElectronic Communication
  310. X.PP
  311. XHere is my address, various net addresses:
  312. X.DS I
  313. XTim Budd
  314. XOregon State University
  315. XDepartment of Computer Science
  316. XCorvallis, Oregon 97331 USA
  317. X(503) 754-3273
  318. X
  319. Xbudd@ cs.orst.edu
  320. X
  321. X{tektronix, hp-pcd} !orstcs!budd
  322. X.DE
  323. X.SH
  324. XChanges
  325. X.PP
  326. XI want to emphasize that this is not even a beta-test version (does that
  327. Xmake it an alpha or a gamma version?).  I will be making a number of
  328. Xchanges, hopefully just additions to the initial image, in the next
  329. Xfew months.  In addition, I hope to prepare versions for other machines,
  330. Xnotably the Macintosh and the IBM PC.  I am also encouraging others to
  331. Xport the system to new machines.  If you have done so, please let me
  332. Xknow.
  333. /
  334. echo 'x - install.ms'
  335. sed 's/^X//' > install.ms << '/'
  336. X.SH
  337. XInstalling Little Smalltalk
  338. X.PP
  339. XFor most users the following simple steps should suffice to build the
  340. Xsystem.
  341. X.IP \(bu
  342. XUnpack the sources.
  343. X.IP \(bu
  344. XEdit the file env.h, changing the metadefine to an already known system
  345. Xtype.
  346. X.IP \(bu
  347. XType \fImake\fP.
  348. X.PP
  349. XThere are a few systems for which more extensive work is required;
  350. Xand of course porting the system to new environments may entail
  351. Xconsiderable work.
  352. XThe remainder of this document is intended to provide more detailed
  353. Xinformation for the curious, and to help those individuals for whom the
  354. Xprevious instructions don't work.
  355. X.SH
  356. XIBM PC and Turbo C
  357. X.PP
  358. XFor these systems there are two small changes that are required, in addition
  359. Xto those noted above.  In the method for saveImage, class Smalltalk, file
  360. Xunix.c, the mode for the open statement must be 'wb', not 'w'.
  361. XAnd in method delete, class File, file unix.c, the command used to delete
  362. Xfiles should be ``DEL'', not ``rm''.
  363. XIt may also be necessary to redefine the value of the global variable
  364. X\fIeditor\fP (set by the script found in file script.ini, used when making
  365. Xthe initial image).  Also the name of a temporary file (found in method
  366. XscratchFile, class File, file unix.st) may have to be changed.
  367. X.SH
  368. XTektronix 4404
  369. X.PP
  370. XThere are several changes that are required to get the system to run on the
  371. X4404.  Start by defining the metadefine constant SYSV in env.h.
  372. XNext, change the Makefile in the following ways,
  373. X.IP \(bu
  374. XTranslate all the .o extensions to .r .
  375. X.IP \(bu
  376. XRemove any CFLAGS definitions.
  377. X.IP \(bu
  378. XChange the rules for parse and st to use +o= notation, which must appear at
  379. Xthe end.  Also add a call on headset, setting the program size to at least
  380. X512K (more if you have it).
  381. X.DS I
  382. Xst: \fIfile names\fP
  383. X    cc \fIfile names\fP +o=st
  384. X    headset st +b=512K
  385. X.DE
  386. X.SH
  387. XPorting to new systems
  388. X.PP
  389. XThere are many ways in which compilers and operating systems differ 
  390. Xfrom each other.
  391. XA fair amount of work has been expanded in making sure the software will
  392. Xoperate on most machines, which requires that different code fragements be
  393. Xused on different systems.  In large part these are controlled by a single
  394. X``meta-define'' in the file env.h.  Setting this one value then causes the
  395. Xexpansion of another code segment, which then defines many more options.
  396. X.PP
  397. XIn the event that you are attempting to port the software to a system that
  398. Xhas not previously been defined, you will need to decide which set of
  399. Xoptions to enable.  The next two sections contain information you may need
  400. Xin making this determination.
  401. X.SH
  402. XDefine Options
  403. X.PP
  404. XMany options are specified merely by giving or not giving a DEFINE
  405. Xstatement in the file env.h.  The following table presents the meaning for
  406. Xeach of these values:
  407. X.de Op
  408. X.IP \\fB\\$1\\fP
  409. X.br
  410. X..
  411. X.Op ALLOC
  412. XDefined If there is an include file called alloc.h which defines calloc, 
  413. Xmalloc, and the like.
  414. X.Op BINREADWRITE
  415. XDefined if the fopen specification for binary files must include the "b"
  416. Xmodifier.  This is true on many MS-DOS inspired systems.
  417. X.Op NOENUMS
  418. XDefined if enumerated datatypes are not supported.  If defined, these will
  419. Xbe replaced by #define constants.
  420. X.Op NOTYPEDEF
  421. XDefined if the typedef construct is not supported.  If defined, these will
  422. Xbe replaced by #define constructs.
  423. X.Op NOVOID
  424. XDefined if the void keyword is not recognized.
  425. XIf defined, expect \fIlint\fP to complain a lot about functions returning
  426. Xvalues which are sometimes (or always) ignored.
  427. X.Op SIGNALS
  428. XUsed if \fIboth\fP the <signals.h> package and the <longjmp.h> package are
  429. Xavilable, and if the routine used to set signals is signal.
  430. XIncompatible with \fBSSIGNALS\fP.
  431. X.Op SSIGNALS
  432. XUsed if \fIboth\fP the <signals.h> package and the <longjmp.h> package are
  433. Xavailable, and if the routine used to set signals is ssignal.
  434. XIncompatible with \fBSIGNALS\fP.
  435. X.Op STRING
  436. XUsed if the string functions (strcpy, strcat and the like) are found in
  437. X<string.h>.  This switch is incompatible with \fBSTRINGS\fP.
  438. X.Op STRINGS
  439. XUsed if the string functions (strcpy, strcat and the like) are found in
  440. X<strings.h>.  This switch is incompatible with \fBSTRING\fP.
  441. X.LP
  442. XIn addition, several routines can optionally be replaced by macros for
  443. Xgreater efficiency.  See the file memory.h for more information.
  444. X.SH
  445. XObject Memory
  446. X.PP
  447. XThere are several datatypes, not directly supported by C, that are used in
  448. Xthe Little Smalltalk system.  The first of these is the datatype byte.
  449. XA byte is an eight bit unsigned (hence positive) quantity.
  450. XOn many systems the appropriate datatype is unsigned char, however on other
  451. Xsystems this declaration is not recognized and other forms may be required.
  452. XTo aid in coverting to and from bytes the macro byteToInt() is used, which
  453. Xconverts a byte value into an integer.  In addition, the routines byteAt
  454. Xand byteAtPut are used to get and put bytes from byte strings.
  455. X.PP
  456. XThe other datatype is that used to represent object points.  On most
  457. Xmachines in which a short is 16 bits, the datatype short should suffice.
  458. XMuch more information on the memory module can be found in the file
  459. Xmemory.h.
  460. X.SH
  461. XOptions in Building the System
  462. X.PP
  463. XTo create the parser type
  464. X.DS I
  465. Xmake parse
  466. X.DE
  467. X.PP
  468. XThe resulting program, called parse, is used to generate the object image
  469. Xinitially loaded into the bytecode interpreter.
  470. X.PP
  471. XNext, make the interpreter itself by typing
  472. X.DS I
  473. Xmake st
  474. X.DE
  475. X.PP
  476. XNote that the interpreter and the parser share some files.
  477. X.PP
  478. XFinally, produce an initial object image.  The image created when you type
  479. X.DS I
  480. Xmake sunix
  481. X.DE
  482. X.LP
  483. Xis the smallest and fastest.  It is a single process version of smalltalk.
  484. XA slower multiprocess version can be created by typing ``make munix''*.
  485. X.FS
  486. X* Multi processing from munix is done entirely in Smalltalk.
  487. XWhile this is a good idea from the point of view of keeping the bytecode
  488. Xinterpreter small and giving one the greatest flexibility, there seems to
  489. Xbe a dramatic performance penalty.  I'm considering the alternatives.
  490. X.FE
  491. XOf more interest, an image containing test cases
  492. Xcan be generated by typing ``make stest''.
  493. XThis command compiles several test cases, then runs st on a script which
  494. Xinvokes all the test cases.  There is a similar command mtest for the
  495. Xmultiprocessing version.
  496. X.PP
  497. XOnce you have created an object image, type 
  498. X.DS I
  499. Xst
  500. X.DE
  501. X.LP
  502. Xto run the system.
  503. XBy default the image file ``imageFile'' is read.  You can optionally
  504. Xuse a different image file by giving the name on the command line following
  505. Xthe st command.
  506. X.SH
  507. XCompiler Bogosities
  508. X.PP
  509. XThis section will detail some of the unnatural actions you may have to
  510. Xperform to get Little Smalltalk to work with a few brain damaged compilers.
  511. XSince there are so few of these, it I see it as a problem more with the
  512. Xcompilers than with the system, the code make no accomodation for these.
  513. X.PP
  514. XOn some older Sequent Balance C compilers, incorrect code is produced for
  515. X.DS I
  516. Xhash %= (objectSize(symbols) / 2)
  517. X.DE
  518. X.LP
  519. XIn the file image.c.  This should be replaced by
  520. X.DS I
  521. Xhash = hash % (objectSize(symbols) / 2)
  522. X.DE
  523. X.PP
  524. XOn many systems external names are restricted to six (or even five!)
  525. Xcharacters.  This causes significant problems.  I have heard of systems
  526. Xwhich automatically generate a sed script to take care of this, but have
  527. Xnot found one yet.  If you know of such a thing let me know.
  528. X.SH
  529. XHelping Others
  530. X.PP
  531. XIf you succeed in getting Little Smalltalk ported to a machine or operating
  532. Xsystem not described in env.h, I would be most pleased to get a listing of
  533. Xthe changes you made.  These can then be incorporated into the latest
  534. Xdistribution.
  535. /
  536. echo 'x - lex.c'
  537. sed 's/^X//' > lex.c << '/'
  538. X/*
  539. X    Little Smalltalk, version 2
  540. X    Written by Tim Budd, Oregon State University, July 1987
  541. X
  542. X    lexical analysis routines for method parser
  543. X    should be called only by parser 
  544. X*/
  545. X
  546. X# include <stdio.h>
  547. X# include <ctype.h>
  548. X# include "env.h"
  549. X# include "memory.h"
  550. X# include "lex.h"
  551. X
  552. Xextern double atof();
  553. X
  554. X/* global variables returned by lexical analyser */
  555. X
  556. Xtokentype token;        /* token variety */
  557. Xchar tokenString[80];        /* text of current token */
  558. Xint tokenInteger;        /* integer (or character) value of token */
  559. Xdouble tokenFloat;        /* floating point value of token */
  560. X
  561. X/* local variables used only by lexical analyser */
  562. X
  563. Xstatic char *cp;        /* character pointer */
  564. Xstatic char pushBuffer[10];    /* pushed back buffer */
  565. Xstatic int  pushindex;        /* index of last pushed back char */
  566. Xstatic char cc;            /* current character */
  567. Xstatic long longresult;        /* value used when building int tokens */
  568. X
  569. X/* lexinit - initialize the lexical analysis routines */
  570. Xnoreturn lexinit(str)
  571. Xchar *str;
  572. X{
  573. X    pushindex = 0;
  574. X    cp = str;
  575. X    /* get first token */
  576. X    ignore nextToken();
  577. X}
  578. X
  579. X/* pushBack - push one character back into the input */
  580. Xstatic pushBack(c)
  581. Xchar c;
  582. X{
  583. X    pushBuffer[pushindex++] = c;
  584. X}
  585. X
  586. X/* nextChar - retrieve the next char, from buffer or input */
  587. Xstatic char nextChar()
  588. X{
  589. X    if (pushindex > 0) cc = pushBuffer[--pushindex];
  590. X    else if (*cp) cc = *cp++;
  591. X    else cc = '\0';
  592. X    return(cc);
  593. X}
  594. X
  595. X/* isClosing - characters which can close an expression */
  596. Xstatic boolean isClosing(c)
  597. Xchar c;
  598. X{
  599. X    switch(c) {
  600. X        case '.': case ']': case ')': case ';':
  601. X            return(true);
  602. X    }
  603. X    return(false);
  604. X}
  605. X
  606. X/* isSymbolChar - characters which can be part of symbols */
  607. Xstatic boolean isSymbolChar(c)
  608. Xchar c;
  609. X{
  610. X    if (isdigit(c) || isalpha(c)) return(true);
  611. X    if (isspace(c) || isClosing(c)) return(false);
  612. X    return(true);
  613. X}
  614. X
  615. X/* singleBinary - binary characters that cannot be continued */
  616. Xstatic boolean singleBinary(c)
  617. Xchar c;
  618. X{
  619. X    switch(c) {
  620. X        case '[': case '(': case ')': case ']':
  621. X            return(true);
  622. X    }
  623. X    return(false);
  624. X}
  625. X
  626. X/* binarySecond - return true if char can be second char in binary symbol */
  627. Xstatic boolean binarySecond(c)
  628. Xchar c;
  629. X{
  630. X    if (isalpha(c) || isdigit(c) || isspace(c) || isClosing(c) ||
  631. X        singleBinary(c))
  632. X        return(false);
  633. X    return(true);
  634. X}
  635. X
  636. Xtokentype nextToken()
  637. X{    char *tp;
  638. X    boolean sign;
  639. X
  640. X    /* skip over blanks and comments */
  641. X    while(nextChar() && (isspace(cc) || (cc == '"')))
  642. X        if (cc == '"') {
  643. X            /* read comment */
  644. X            while (nextChar() && (cc != '"')) ;
  645. X            if (! cc) break;    /* break if we run into eof */
  646. X            }
  647. X
  648. X    tp = tokenString;
  649. X    *tp++ = cc;
  650. X
  651. X    if (! cc)            /* end of input */
  652. X        token = inputend;
  653. X    
  654. X    else if (isalpha(cc)) {        /* identifier */
  655. X        while (nextChar() && isalnum(cc))
  656. X            *tp++ = cc;
  657. X        if (cc == ':') {
  658. X            *tp++ = cc;
  659. X            token = namecolon;
  660. X            }
  661. X        else {
  662. X            pushBack(cc);
  663. X            token = nameconst;
  664. X            }
  665. X        }
  666. X
  667. X    else if (isdigit(cc)) {        /* number */
  668. X        longresult = cc - '0';
  669. X        while (nextChar() && isdigit(cc)) {
  670. X            *tp++ = cc;
  671. X            longresult = (longresult * 10) + (cc - '0');
  672. X            }
  673. X        if (longCanBeInt(longresult)) {
  674. X            tokenInteger = longresult;
  675. X            token = intconst;
  676. X            }
  677. X        else {
  678. X            token = floatconst;
  679. X            tokenFloat = (double) longresult;
  680. X            }
  681. X        if (cc == '.') {    /* possible float */
  682. X            if (nextChar() && isdigit(cc)) {
  683. X                *tp++ = '.';
  684. X                do
  685. X                    *tp++ = cc;
  686. X                while (nextChar() && isdigit(cc));
  687. X                if (cc) pushBack(cc);
  688. X                token = floatconst;
  689. X                *tp = '\0';
  690. X                tokenFloat = atof(tokenString);
  691. X                }
  692. X            else {
  693. X                /* nope, just an ordinary period */
  694. X                if (cc) pushBack(cc);
  695. X                pushBack('.');
  696. X                }
  697. X            }
  698. X        else
  699. X            pushBack(cc);
  700. X
  701. X        if (nextChar() && cc == 'e') {    /* possible float */
  702. X            if (nextChar() && cc == '-') {
  703. X                sign = true;
  704. X                ignore nextChar();
  705. X                }
  706. X            else
  707. X                sign = false;
  708. X            if (cc && isdigit(cc)) { /* yep, its a float */
  709. X                *tp++ = 'e';
  710. X                if (sign) *tp++ = '-';
  711. X                while (cc && isdigit(cc)) {
  712. X                    *tp++ = cc;
  713. X                    ignore nextChar();
  714. X                    }
  715. X                if (cc) pushBack(cc);
  716. X                *tp = '\0';
  717. X                token = floatconst;
  718. X                tokenFloat = atof(tokenString);
  719. X                }
  720. X            else {    /* nope, wrong again */
  721. X                if (cc) pushBack(cc);
  722. X                if (sign) pushBack('-');
  723. X                pushBack('e');
  724. X                }
  725. X            }
  726. X            else
  727. X                if (cc) pushBack(cc);
  728. X        }
  729. X
  730. X    else if (cc == '$') {        /* character constant */
  731. X        tokenInteger = (int) nextChar();
  732. X        token = charconst;
  733. X        }
  734. X
  735. X    else if (cc == '#') {        /* symbol */
  736. X        tp--;    /* erase pound sign */
  737. X        if (nextChar() == '(')
  738. X            token = arraybegin;
  739. X        else {
  740. X            pushBack(cc);
  741. X            while (nextChar() && isSymbolChar(cc))
  742. X                *tp++ = cc;
  743. X            pushBack(cc);
  744. X            token = symconst;
  745. X            }
  746. X        }
  747. X
  748. X    else if (cc == '\'') {        /* string constant */
  749. X        tp--;    /* erase pound sign */
  750. X        strloop:
  751. X        while (nextChar() && (cc != '\''))
  752. X            *tp++ = cc;
  753. X        /* check for nested quote marks */
  754. X        if (cc && nextChar() && (cc == '\'')) {
  755. X            *tp++ = cc;
  756. X            goto strloop;
  757. X            }
  758. X        pushBack(cc);
  759. X        token = strconst;
  760. X        }
  761. X
  762. X    else if (isClosing(cc))        /* closing expressions */
  763. X        token = closing;
  764. X
  765. X    else if (singleBinary(cc)) {    /* single binary expressions */
  766. X        token = binary;
  767. X        }
  768. X
  769. X    else {                /* anything else is binary */
  770. X        if (nextChar() && binarySecond(cc))
  771. X            *tp++ = cc;
  772. X        else
  773. X            pushBack(cc);
  774. X        token = binary;
  775. X        }
  776. X
  777. X    *tp = '\0';
  778. X    return(token);
  779. X}
  780. /
  781. echo 'x - names.c'
  782. sed 's/^X//' > names.c << '/'
  783. X/*
  784. X    Little Smalltalk, version 2
  785. X    Written by Tim Budd, Oregon State University, July 1987
  786. X
  787. X    Name Table module
  788. X
  789. X    A name table is the term used for a Dictionary indexed by symbols.
  790. X    There are two name tables used internally by the bytecode interpreter.
  791. X    The first is the table, contained in the variable globalNames,
  792. X    that contains the names and values of all globally accessible 
  793. X    identifiers.  The second is the table of methods associated with
  794. X    every class.  Notice that in neither of these cases does the
  795. X    system ever put anything INTO the tables, thus there are only
  796. X    routines here for reading FROM tables.
  797. X
  798. X    (putting things INTO the table is all done in Smalltalk code,
  799. X    using the methods from class Dictionary)
  800. X
  801. X    One complication of instances of class Symbol is that all
  802. X    symbols must be unique, not only so that == will work as expected,
  803. X    but so that memory does not get overly clogged up with symbols.
  804. X    Thus all symbols are kept in a hash table, and when new symbols
  805. X    are created (via newSymbol(), below) they are inserted into this
  806. X    table, if not already there.
  807. X
  808. X    This module also manages the definition of various symbols that are
  809. X    given fixed values for efficiency sake.  These include the objects
  810. X    nil, true, false, and various classes.
  811. X*/
  812. X
  813. X# include <stdio.h>
  814. X# include "env.h"
  815. X# include "memory.h"
  816. X# include "names.h"
  817. X
  818. X/* global variables used to avoid repeated examinations of the global symbol table */
  819. Xobject trueobj = nilobj;    /* the pseudo variable true */
  820. Xobject falseobj = nilobj;    /* the pseudo variable false */
  821. Xobject smallobj = nilobj;    /* the pseudo variable smalltalk */
  822. Xobject arrayclass = nilobj;    /* the class ``Array'' */
  823. Xobject blockclass = nilobj;    /* the class ``Block'' */
  824. Xobject contextclass = nilobj;    /* the class ``Context'' */
  825. Xobject intclass = nilobj;    /* the class ``Integer'' */
  826. Xobject intrclass = nilobj;    /* the class ``Interpreter'' */
  827. Xobject symbolclass = nilobj;    /* the class ``Symbol'' */
  828. Xobject stringclass = nilobj;    /* the class ``String'' */
  829. X
  830. X/*
  831. X    some messages are encoded in concise bytecode format -
  832. Xto reduce the size of the compiled methods
  833. X(also, in some cases, to more efficiently detect special cases
  834. Xhandled in the interpreter, rather than by methods)
  835. X*/
  836. X
  837. Xchar *binStrs[] = {"+", "-", "<", ">", "<=", ">=", "=", "~=", "*", 
  838. X"quo:", "rem:", "bitAnd:", "bitXor:", 
  839. X"==", ",", "at:", "basicAt:", "do:", "coerce:", "error:", "includesKey:",
  840. X"isMemberOf:", "new:", "to:", "value:", "whileTrue:", "addFirst:", "addLast:",
  841. X0};
  842. X
  843. Xobject binSyms[28];
  844. X
  845. Xchar *unStrs[] = {"isNil", "notNil", "new", "value", "class", "size",
  846. X"basicSize", "print", "printString", 0};
  847. X
  848. Xobject unSyms[9];
  849. X
  850. Xchar *keyStrs[] = {"at:ifAbsent:", "at:put:", "basicAt:put:", "between:and:",
  851. X0};
  852. X
  853. Xobject keySyms[4];
  854. X
  855. Xobject nameTableLookup(dict, symbol)
  856. Xobject dict, symbol;
  857. X{    int hash, tablesize;
  858. X    object table, link;
  859. X
  860. X    /* first get hash table */
  861. X    table = basicAt(dict, 1);
  862. X
  863. X    /* now see if table is valid */
  864. X    if ((tablesize = objectSize(table)) < 3)
  865. X        sysError("system error","lookup on null table");
  866. X    else {
  867. X        hash = 3 * ( symbol % (tablesize / 3));
  868. X        if (basicAt(table, hash+1) == symbol)
  869. X            return(basicAt(table, hash+2));
  870. X
  871. X        /* otherwise look along the chain of links */
  872. X        for (link=basicAt(table, hash+3); link != nilobj; 
  873. X                    link=basicAt(link, 3))
  874. X            if (basicAt(link, 1) == symbol)
  875. X                return(basicAt(link, 2));
  876. X
  877. X    }
  878. X    return (nilobj);
  879. X}
  880. X
  881. Xobject getClass(obj)
  882. Xobject obj;
  883. X{
  884. X    if (isInteger(obj))
  885. X        return(intclass);
  886. X    return (classField(obj));
  887. X}
  888. X
  889. Xstatic object globalGet(name)
  890. Xchar *name;
  891. X{    object newobj;
  892. X
  893. X    newobj = globalSymbol(name);
  894. X    if (newobj == nilobj)
  895. X        sysError("symbol not found in image", name);
  896. X    return(newobj);
  897. X}
  898. X
  899. Xnoreturn initCommonSymbols()
  900. X{    int i;
  901. X
  902. X    trueobj = globalGet("true");
  903. X    falseobj = globalGet("false");
  904. X    smallobj  = globalGet("smalltalk");
  905. X    arrayclass = globalGet("Array");
  906. X    blockclass = globalGet("Block");
  907. X    contextclass = globalGet("Context");
  908. X    intclass = globalGet("Integer");
  909. X    symbolclass = globalGet("Symbol");
  910. X    stringclass = globalGet("String");
  911. X    /* interpreter may or may not be there */
  912. X    intrclass = globalSymbol("Interpreter");
  913. X
  914. X    for (i = 0; i < 28; i++)
  915. X        binSyms[i] = newSymbol(binStrs[i]);
  916. X
  917. X    for (i = 0; i < 9; i++)
  918. X        unSyms[i] = newSymbol(unStrs[i]);
  919. X
  920. X    for (i = 0; i < 4; i++)
  921. X        keySyms[i] = newSymbol(keyStrs[i]);
  922. X}
  923. X
  924. Xobject newArray(size)
  925. Xint size;
  926. X{    object newobj;
  927. X
  928. X    if (arrayclass == nilobj) {
  929. X        arrayclass = globalSymbol("Array");
  930. X        if (arrayclass == nilobj) 
  931. X            sysError("can't find global symbol","Array");
  932. X        }
  933. X    newobj = allocObject(size);
  934. X    setClass(newobj, arrayclass);
  935. X    return(newobj);
  936. X}
  937. X
  938. Xobject newSymbol(str)
  939. Xchar *str;
  940. X{    int hash;
  941. X    object newSym, link;
  942. X    char *p;
  943. X
  944. X    /* first compute hash value of string text */
  945. X    /* this is duplicated in image.c - make sure any changes match there */
  946. X    hash = 0;
  947. X    for (p = str; *p; p++)
  948. X        hash += *p;
  949. X    if (hash < 0) hash = - hash;
  950. X    hash = 2 * ( hash % (objectSize(symbols) / 2));
  951. X
  952. X    /* next look to see if it is in symbols - note that this
  953. X       text duplicates that found in nameTableLookup, only using
  954. X       string comparison instead of symbol comparison */
  955. X    newSym = basicAt(symbols, hash+1);
  956. X    if (newSym && streq(str, charPtr(newSym)))
  957. X        return(newSym);
  958. X
  959. X    /* not in table, look along links */
  960. X    for (link=basicAt(symbols, hash+2); link != nilobj; link=basicAt(link,2)) {
  961. X        newSym = basicAt(link, 1);
  962. X        if (streq(str, charPtr(newSym)))
  963. X            return(newSym);
  964. X        }
  965. X
  966. X    /* not found, make a new symbol */
  967. X    newSym = allocSymbol(str);
  968. X    setClass(newSym, symbolclass);
  969. X
  970. X    /* now insert new symbol in table, so next time we will find it */
  971. X    if (basicAt(symbols, hash+1) == nilobj)
  972. X        basicAtPut(symbols, hash+1, newSym);
  973. X    else {        /* insert along links */
  974. X        link = allocObject(2);
  975. X        basicAtPut(link, 1, newSym);
  976. X        basicAtPut(link, 2, basicAt(symbols, hash+2));
  977. X        basicAtPut(symbols, hash+2, link);
  978. X        }
  979. X
  980. X    return(newSym);
  981. X}
  982. X
  983. Xobject newStString(value)
  984. Xchar *value;
  985. X{    object newobj;
  986. X
  987. X    newobj = allocSymbol(value);
  988. X    setClass(newobj, stringclass);
  989. X    return(newobj);
  990. X}
  991. X
  992. Xobject newFloat(d)
  993. Xdouble d;
  994. X{    object newobj;
  995. X
  996. X    newobj = allocFloat(d);
  997. X    setClass(newobj, globalSymbol("Float"));
  998. X    return(newobj);
  999. X}
  1000. /
  1001. echo 'x - todo'
  1002. sed 's/^X//' > todo << '/'
  1003. XThings to do
  1004. X
  1005. XWrite infinite precision number package.
  1006. X
  1007. XAdd traceback (unfortunately, this must be done in the interpreter, not
  1008. Xin Smalltalk code).
  1009. X
  1010. XAdd descriptions to classes (to be displayed by display)
  1011. X
  1012. Xflush message cache shouldn't flush everything, just one entry.
  1013. X
  1014. Xchange process manager to use alloca, if available (this would allow
  1015. Xprocesses to run as deep as the process stack, instead of the artificial
  1016. Xlimitation now imposed).
  1017. X
  1018. Xadd methods to class Class so that assigning variables: or changing
  1019. Xsuperclass will automatically recompile all methods.
  1020. X
  1021. XMake files a subclass of collection  (to be useful, requires adding more
  1022. Xfunctionality to files).
  1023. X
  1024. Xmodify the parser so that it can add to an existing image.
  1025. X
  1026. XDone
  1027. X
  1028. XClass File now added, changes interface to use files.
  1029. XInteger arith ops now trap overflows
  1030. XAllowed non-alpha tokens (such as #+ )
  1031. XFixed doEdit so that it allows you to retry.
  1032. XFixed parser so that optimized messages don't require [ ] around args.
  1033. XFixed parser so that empty blocks work correctly
  1034. XTraps interrups and restarts gracefully now.
  1035. XCreated much better user interface
  1036. XFixed bug in lexer, preventing reading past end of input
  1037. X
  1038. Xmessages added:
  1039. X    display (for classes and collections)
  1040. X    respondsTo (for symbols)
  1041. X    changed indexOf to take a block, rather than a value
  1042. X    class addSubClass
  1043. X    smalltalk inquire:
  1044. /
  1045. echo 'x - top.ms'
  1046. sed 's/^X//' > top.ms << '/'
  1047. X.SH
  1048. XWho's On Top?
  1049. X.PP
  1050. XOne of the most important decisions to be made in designing a new user
  1051. Xinterface (or front end) for the Little Smalltalk system is whether the user
  1052. Xinterface management code should sit on top of the Smalltalk bytecode 
  1053. Xinterpreter, setting up commands and invoking the interpreter to execute them,
  1054. Xor underneith the bytecode interpreter, being invoked by Smalltalk, via the
  1055. Xmechanism of primitive methods.  Both schemes have advantages and disadvantages
  1056. Xwhich we will discuss in this essay.
  1057. X.PP
  1058. XIn a simple interface, placing Smalltalk on top is often easier.  The main
  1059. Xdriver need only set up one initial call to the Smalltalk bytecode interpreter,
  1060. Xand thereafter everything is done in Smalltalk.  For example, we might put
  1061. Xinitialization code in a method in class \fBSmalltalk\fP, as follows:
  1062. X.DS L
  1063. XClass Smalltalk
  1064. X    getString
  1065. X        \(ua <1>
  1066. X|
  1067. X    run        | string |
  1068. X        [ '>    ' printNoReturn.
  1069. X           string <- smalltalk getString. 
  1070. X           string notNil ]
  1071. X            whileTrue: [ (string size > 0)
  1072. X                    ifTrue: [ smalltalk doIt: string ] ]
  1073. X]
  1074. X.DE
  1075. X.PP
  1076. XOnce the bytecode interpreter is started on the method \fBrun\fP, it will
  1077. Xloop continuously, reading commands from the user (via the method 
  1078. X\fBgetString\fP) and executing them (via the method \fBdoIt:\fP).
  1079. XPresumably the user has some way of indicating end of input, such as the
  1080. Xunix control-D convention, which causes \fBgetString\fP to return the
  1081. Xvalue nil.  The \fIif\fP statement inside the while loop
  1082. Xinsures that if the user simply hits the return key execution will quickly 
  1083. Xloop back to the prompt.
  1084. X.PP
  1085. XBesides making the initialization for the Little Smalltalk system easy,
  1086. Xthis approach also has the advantage of putting more code into Smalltalk
  1087. Xitself, where the user can see it and (presumably) modify it if they wish.
  1088. XA general guideline is that it is better to put as much into Smalltalk
  1089. Xas possible, since Smalltalk is easier to write and the bytecode representation
  1090. Xusually smaller than the equivalent code in C.
  1091. XNever the less, there are valid reasons why an implementor might choose
  1092. Xa different technique.
  1093. X.PP
  1094. XFor example, if there are many other activities which should command the 
  1095. Xattention of the controlling program (window updates, mouse motions) the 
  1096. XSmalltalk code may not be able to respond fast enough, or might become too 
  1097. Xlarge and complex to be workable.
  1098. XIn this case the only alternative is to have the front end respond directly
  1099. Xto events, and only invoke the Smalltalk interpreter as time permits.
  1100. XIn basic terms, the front end would perform the loop written in the method
  1101. X\fBinit\fP shown above (along with handling various other tasks), and then 
  1102. Xcall upon the method in class \fBSmalltalk\fP
  1103. Xto execute the message \fBdoIt:\fP.
  1104. X.SH
  1105. XHow to Do It
  1106. X.PP
  1107. XIn either of the two schemes described above, an important message is 
  1108. X\fBdoIt:\fP, which takes a string (presumably representing a Smalltalk
  1109. Xexpression) and performs it.  An easy way to perform this message is to
  1110. Xmake a method out of the expression, by appending a message pattern
  1111. Xon front, and then pass the string to the method parser.  If the method
  1112. Xparser is successful, the method can then be executed.
  1113. X.DS L
  1114. XdoIt: aString        | method |
  1115. X    method <- Method new.
  1116. X    method text: ( 'proceed ', aString ).
  1117. X    (method compileWithClass: Smalltalk)
  1118. X        ifTrue: [ method executeWith: #( 0 ) ]
  1119. X.DE
  1120. X.PP
  1121. XThe message \fBcompileWithClass:\fP compiles the method as if it was
  1122. Xappearing as part of class Smalltalk.  If compilation is successful,
  1123. Xthe message \fBexecuteWith:\fP executes the message, using as arguments
  1124. Xthe array #(0).  The array that accompanies this message must have at
  1125. Xleast one element, as the first value is used as the receiver for
  1126. Xthe method.
  1127. XSimilar techniques can be used for the message \fBprintIt:\fP, if desired.
  1128. X.SH
  1129. XThe Other End
  1130. X.PP
  1131. XThe opposite extreme from the front end are those messages that originate
  1132. Xwithin the bytecode interpreter and must be communicated to the user.
  1133. XWe can divide these values into four categories:
  1134. X.IP 1.
  1135. XSystem errors.  These are all funnelled through the routine sysError(), found
  1136. Xin memory.c.  System errors are caused by dramatically wrong conditions,
  1137. Xand should generally cause the system to abort after printing the message
  1138. Xpassed as argument to sysError().
  1139. X.IP 2.
  1140. XCompiler errors.  As we noted above, the method compiler is used to
  1141. Xparse expressions typed directly at the keyboard, so these message can
  1142. Xalso arise in that manner.  These are all funnelled through the routine
  1143. XcompilError(), found in parse.c.  These should print their arguments 
  1144. X(two strings), in an appropriate location on the users screen.
  1145. XExecution continues normally after call.
  1146. X.IP 3.
  1147. XVarious primitives, found in primitive.c, are also used to print strings
  1148. Xon the users terminal.  In particular, an appropriate meaning should be
  1149. Xgiven to the message \fBprint\fP in class \fBString\fP.  What appropriate
  1150. Xmeans is undoubtedly implementation specific.
  1151. X.IP 4.
  1152. XFinally, and perhaps most importantly, there must be some means provided
  1153. Xto allow users to enter and edit methods.  The interface for this task
  1154. Xis standard; instances of class \fBClass\fP must respond to the messages
  1155. X\fBaddMethod\fP and \fBeditMethod:\fP, the latter taking as argument a
  1156. Xsymbol representing the name of a method.  How they achieve their two
  1157. Xtasks is, however, implementation specific.
  1158. XUnder Unix, a simple implementation adds a new primitive for Strings;
  1159. Xthis primitive copies the string into a temporary file, starts up the
  1160. Xeditor on the file, and returns the contents of the file when the user
  1161. Xexits the editor.  Having this capability, the method editing code
  1162. Xcan be given as follows.  In class \fBClass\fP:
  1163. X.DS L
  1164. X    addMethod
  1165. X        self doEdit: ''
  1166. X|
  1167. X    editMethod: name        | theMethod |
  1168. X        theMethod <- methods at: name
  1169. X                ifAbsent: [ 'no such method ' print. \(ua nil ].
  1170. X        self doEdit: theMethod text
  1171. X|
  1172. X    doEdit: startingText        | theMethod |
  1173. X        theMethod <- Method new;
  1174. X            text: startingText edit.
  1175. X        (theMethod compileWithClass: self)
  1176. X            ifTrue: [ methods at: theMethod name put: theMethod ]
  1177. X.DE
  1178. X.LP
  1179. XAnd in class \fBString\fP:
  1180. X.DS L
  1181. X    edit
  1182. X        \(ua <19 self>
  1183. X.DE
  1184. X.LP
  1185. XHere primitive 19 performs all the tasks of creating the temporary file,
  1186. Xstarting the editor, and creating the string representing the file
  1187. Xcontents when the editor is exited.
  1188. X.PP
  1189. XAlternative techniques, for example using windowing, would undoubtedly
  1190. Xbe more complicated.
  1191. /
  1192. echo 'x - unix.st'
  1193. sed 's/^X//' > unix.st << '/'
  1194. X*
  1195. X* Little Smalltalk, version 2
  1196. X* Written by Tim Budd, Oregon State University, July 1987
  1197. X*
  1198. X*  methods for the unix front end - single process version
  1199. X*
  1200. X*    (override previous declaration, adding new instance variable)
  1201. XDeclare Smalltalk Object errorRecoveryBlock
  1202. XDeclare File Object name pointer
  1203. X*    (better override global variable as well )
  1204. XInstance Smalltalk smalltalk
  1205. X*     make global variables for standard files
  1206. XInstance File stdin
  1207. XInstance File stdout
  1208. XInstance File stderr
  1209. X*
  1210. XClass File
  1211. X    asString    | text line |
  1212. X        text <- ''.
  1213. X        [line <- self getString. line notNil]
  1214. X            whileTrue: [ text <- text , line ].
  1215. X        ^ text
  1216. X|
  1217. X    name: string
  1218. X        name <- string
  1219. X|
  1220. X    name
  1221. X        ^ name
  1222. X|
  1223. X    scratchFile
  1224. X        name <- 'junk.tmp'
  1225. X|
  1226. X    open: mode
  1227. X        pointer <- <120 name mode>.
  1228. X        pointer isNil
  1229. X            ifTrue: [ smalltalk error: 'open failed']
  1230. X|
  1231. X    close
  1232. X        (pointer notNil)
  1233. X            ifTrue: [<121 pointer>].
  1234. X        pointer <- nil.
  1235. X|
  1236. X    delete
  1237. X        ('rm ', name) unixCommand
  1238. X|
  1239. X    fileIn        | line |
  1240. X        [ line <- self getString. line notNil ]
  1241. X            whileTrue: [ line <- line words: 
  1242. X                [:x | x isAlphabetic ] .
  1243. X                     Switch new; key: (line at: 1);
  1244. X            ifMatch: 'Class' do: [self fileInClass: line ] ;
  1245. X            ifMatch: 'Method' do: 
  1246. X                    [ self fileInMethod: line ] ;
  1247. X                else: [ ^ smalltalk error: 
  1248. X                    'invalid format for fileIn'] ]
  1249. X|
  1250. X    fileInClass: commandLine    | name |
  1251. X        name <- (commandLine at: 2
  1252. X            ifAbsent: [^ smalltalk error:
  1253. X                'missing class name in Class directive'])
  1254. X                    asSymbol.
  1255. X        globalNames at: name put: ( Class new;
  1256. X            name: name;
  1257. X            superClass: (globalNames at: (
  1258. X                commandLine at: 3
  1259. X                ifAbsent: [ ^ smalltalk error:
  1260. X                    'missing superclass name'])
  1261. X                    asSymbol
  1262. X                ifAbsent: [ ^ smalltalk error:
  1263. X                    'unknown class']);
  1264. X            variables: (commandLine copyFrom: 4 to:
  1265. X                    commandLine size ) )
  1266. X|
  1267. X    fileInMethod: commandLine
  1268. X        (commandLine size ~= 2)
  1269. X            ifTrue: [ ^ smalltalk error: 
  1270. X                'invalid Method command line '].
  1271. X            (globalNames at: (commandLine at: 2) asSymbol
  1272. X                ifAbsent: [ ^ smalltalk error:
  1273. X                    'unknown class in Method header'])
  1274. X                fileInMethod: self
  1275. X|
  1276. X    getString
  1277. X        ^ (pointer notNil)
  1278. X            ifTrue: [<125 pointer>]
  1279. X|
  1280. X    getPrompt: aString
  1281. X        stdout printNoReturn: aString.
  1282. X        ^ self getString
  1283. X|
  1284. X    inquire: aString    | response |
  1285. X        response <- self getPrompt: aString.
  1286. X        response isNil 
  1287. X            ifTrue: [ ^ false ].
  1288. X        ^ 'yY' includes: (response at: 1 ifAbsent: [])
  1289. X|
  1290. X    print: aString
  1291. X        (pointer notNil)
  1292. X            ifTrue: [<129 pointer aString>]
  1293. X            ifFalse: [smalltalk error: 'file not open']
  1294. X|
  1295. X    printNoReturn: aString
  1296. X        (pointer notNil)
  1297. X            ifTrue: [<128 pointer aString>]
  1298. X            ifFalse: [smalltalk error: 'file not open']
  1299. X|
  1300. X    readUntil: conditionBlock doing: actionBlock    | line |
  1301. X        [ line <- self getString. line notNil]
  1302. X            whileTrue: [ (conditionBlock value: line)
  1303. X                    ifTrue: [ ^ line ].
  1304. X                    actionBlock value: line ].
  1305. X        ^ nil
  1306. X|
  1307. X    saveImage
  1308. X        (pointer notNil)
  1309. X            ifTrue: [<127 pointer>]
  1310. X            ifFalse: [smalltalk error: 'file not open']
  1311. X]
  1312. XClass Method
  1313. X    executeWith: arguments
  1314. X        ^ ( Context new ; method: self ; 
  1315. X            temporaries: ( Array new: temporarySize) ;
  1316. X            arguments: arguments )
  1317. X           executeFrom: 0 creator: nil
  1318. X]
  1319. XClass Class
  1320. X    addMethod
  1321. X        self doEdit: ''
  1322. X|
  1323. X    addSubClass        | name |
  1324. X        name <- (stdin getPrompt: 'Class Name? ') asSymbol.
  1325. X        globalNames at: name put: 
  1326. X            ( Class new; name: name ; superClass: self ;
  1327. X                readInstanceVariables; readMethods )
  1328. X|
  1329. X    addMethodText: text        | theMethod |
  1330. X        theMethod <- Method new; text: text.
  1331. X        (theMethod compileWithClass: self)
  1332. X            ifTrue: [ methods at: theMethod name put: theMethod.
  1333. X                  smalltalk flushMessageCache.
  1334. X                  ^ true ].
  1335. X        ^ false
  1336. X|
  1337. X    doEdit: startingText        | text |
  1338. X        text <- startingText.
  1339. X        [ text <- text edit.
  1340. X          (self addMethodText: text)
  1341. X            ifTrue: [ false ]
  1342. X            ifFalse: [ stdin inquire: 'edit again (yn) ? ' ]
  1343. X                ] whileTrue
  1344. X|
  1345. X    display
  1346. X        ('Class name: ', name asString)  print.
  1347. X        (superClass notNil)
  1348. X            ifTrue: [ ('Superclass: ', superClass ) print ].
  1349. X        'Instance Variables:' print.
  1350. X        variables isNil
  1351. X            ifTrue: [ 'no instance variables ' print ]
  1352. X            ifFalse: [ variables display ].
  1353. X        'Subclasses: ' print.
  1354. X        self subClasses display
  1355. X|
  1356. X    editMethod: name
  1357. X        self doEdit: ( methods at: name
  1358. X            ifAbsent: [ 'no such method ' print. ^ nil ] ) text
  1359. X|
  1360. X    fileInMethod: file    | text line |
  1361. X        text <- ''.
  1362. X        line <- file readUntil: [:x | '|[' includes: 
  1363. X                    (x at: 1 ifAbsent: [] ) ]
  1364. X                doing: [:x | text <- text , x].
  1365. X        self addMethodText: text.
  1366. X        ^ line
  1367. X|
  1368. X    fileOut: file
  1369. X        file printNoReturn: 'Class ', name asString.
  1370. X        file printNoReturn: ' ', superClass name asString.
  1371. X        variables do: [:x | file printNoReturn: ' ', x ].
  1372. X        file print: ''.
  1373. X        methods do: [:x | self fileOutMethod: x name to: file ]
  1374. X|
  1375. X    fileOutMethod: method to: file
  1376. X        file print: 'Method ', name asString.
  1377. X        file print: (methods at: method
  1378. X            ifAbsent: [^ smalltalk error:
  1379. X                'no such method' ]) text.
  1380. X        file print: '|'
  1381. X|
  1382. X    readInstanceVariables
  1383. X        self variables:
  1384. X            ((stdin getPrompt: 'Instance Variables? ')
  1385. X            words: [:x | x isAlphabetic ])
  1386. X|
  1387. X    readMethods
  1388. X        [ stdin inquire: 'Add a method (yn) ? ' ]
  1389. X            whileTrue: [ self addMethod ]
  1390. X|
  1391. X    viewMethod: name
  1392. X        (methods at: name
  1393. X            ifAbsent: [ 'no such method ' print. ^ nil ]) text print
  1394. X]
  1395. XClass Smalltalk
  1396. X    error: aString
  1397. X        stderr print: 'Error: ',aString.
  1398. X        errorRecoveryBlock value
  1399. X|
  1400. X    openFiles
  1401. X        stdin name: 'stdin'.
  1402. X        stdin open: 'r'.
  1403. X        stdout name: 'stdout'.
  1404. X        stdout open: 'w'.
  1405. X        stderr name: 'stderr'.
  1406. X        stderr open: 'w'.
  1407. X|
  1408. X    commandLoop    | string |
  1409. X        self openFiles.
  1410. X        [ string <- stdin getPrompt: '>    '. string notNil ]
  1411. X            whileTrue: [ (string size strictlyPositive)
  1412. X                    ifTrue: [ self doIt: string ] ]
  1413. X|
  1414. X    doIt: aString        | method |
  1415. X        errorRecoveryBlock <- [ ^ nil ].
  1416. X        method <- Method new.
  1417. X        method text: ( 'proceed ', aString ).
  1418. X        (method compileWithClass: Object)
  1419. X            ifTrue: [ method executeWith: #( 1 ) ]
  1420. X|
  1421. X    saveImage        | name |
  1422. X        name <- stdin getPrompt: 'type image name: '.
  1423. X        File new;
  1424. X            name: name;
  1425. X            open: 'w';
  1426. X            saveImage;
  1427. X            close.
  1428. X        ('image ', name, ' created') print
  1429. X]
  1430. XClass String
  1431. X    edit    | file text |
  1432. X        file <- File new; 
  1433. X            scratchFile;
  1434. X            open: 'w';
  1435. X            print: self;
  1436. X            close.
  1437. X        (editor, ' ', file name) unixCommand.
  1438. X        file open: 'r'.
  1439. X        text <- file asString.
  1440. X        file close; delete.
  1441. X        ^ text
  1442. X|
  1443. X    print
  1444. X        ^ stdout print: self
  1445. X|
  1446. X    unixCommand
  1447. X        ^ <88 self>
  1448. X]
  1449. /
  1450. echo 'Part 04 of small.v2 complete.'
  1451. exit
  1452.