home *** CD-ROM | disk | FTP | other *** search
- Subject: v13i056: New release of little smalltalk, Part04/05
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Tim Budd <budd@MIST.CS.ORST.EDU>
- Posting-number: Volume 13, Issue 56
- Archive-name: little-st2/part04
-
- #!/bin/sh
- #
- #
- # This is version 2.02 of Little Smalltalk, distributed in five parts.
- #
- # This version is dated 12/25/87
- #
- # Several bugs and many features and improvements have been made since the
- # first posting to comp.src.unix. See the file ``todo'' for a partial list.
- #
- # Comments, bug reports, and the like should be submitted to:
- # Tim Budd
- # Smalltalk Distribution
- # Department of Computer Science
- # Oregon State University
- # Corvallis, Oregon
- # 97330
- #
- # budd@cs.orst.edu
- # {hp-pcd, tektronix}!orstcs!budd
- #
- #
- echo 'Start of small.v2, part 04 of 05:'
- echo 'x - at.ms'
- sed 's/^X//' > at.ms << '/'
- X.LP
- X(note: this is the first of a series of essays descriging how various
- Xfeatures of the Little Smalltalk bytecodes work).
- X.SH
- XWhere It's At
- X.PP
- XThis short note explains how the messages \fBat:\fP, \fBat:put:\fP, and their
- Xrelatives are defined and used in collections. We start by discussing the
- Xsimplest form of collections, arrays and strings.
- X.PP
- XThe message \fBat:\fP is not defined anywhere in class \fBArray\fP or any of
- Xits subclasses. Instead, this message is inherited from
- Xclass \fBCollection\fP, which defines it using the following method:
- X.DS I
- X\fBat:\fP index
- X \(ua self at: index
- X ifAbsent: [ smalltalk error: 'index to at: illegal' ]
- X.DE
- X.PP
- XThe functioning of the message \fBerror:\fP is the topic of another essay;
- Xit is sufficient for our purposes to note only that this message prints out
- Xthe error string and returns nil. By redefining \fBat:\fP in this fashion,
- Xthe subclasses of \fBCollection\fP need not be concerned about how to deal
- Xwith errors in cases where no error recovery action has been specified.
- X.PP
- XFor an array, an index is out of bounds if it is either less than 1 or greater
- Xthan the size of the array. This is tested by a method in class \fBArray\fP:
- X.DS I
- X\fBincludesKey:\fP index
- X ^ index between: 1 and: self size
- X.DE
- X.PP
- XThe message \fBsize\fP is defined in class \fBArray\fP in terms of the
- Xmessage \fBbasicSize\fP
- X.DS I
- X\fBsize\fP
- X ^ self basicSize
- X.DE
- X.PP
- XThe message \fBbasicSize\fP (as well as \fBbasicAt:\fP, discussed below)
- Xis inherited from class
- X\fBObject\fP. It can be used on any object; on non-arrays it returns
- Xthe number of instance variables for the object. The messages \fBbasicSize\fP
- Xand \fBbasicAt:put:\fP can be used by system
- Xclasses, for example debuggers, to access instance variables in an object
- Xwithout having explicit access to the instance variables. One must be
- Xcareful, however,
- X\fBbasicAt:\fP produces a system error, and not a Smalltalk error message,
- Xif it is given an index value that is out of range.
- X.PP
- XUsing \fBincludesKey:\fP for a test, a value is only accessed if the index
- Xis legal. The following method appears in class \fBArray\fP:
- X.DS I
- X\fBat:\fP index \fBifAbsent:\fP exceptionBlock
- X ^ (self includesKey: index)
- X ifTrue: [ self basicAt: index ]
- X ifFalse: [ exceptionBlock value ]
- X.DE
- X.PP
- XA subclass of \fBArray\fP is the class \fBByteArray\fP. A byte array is a form
- Xof array in which the elements can only take on values from zero to 255, or
- Xto put it another way, values that can be stored in one byte.
- XOn most 16 bit machines, we can store two such bytes in the space it takes
- Xto store one object pointer. Thus, the message \fBsize\fP is redefined
- Xin class \fBByteArray\fP as follows:
- X.DS I
- X\fBsize\fP
- X \(ua self basicSize * 2
- X.DE
- X.LP
- XNote that this implies that byte arrays always have an even number of
- Xelements. Next the message \fBbasicAt:\fP is redefined to use a byte,
- Xinstead of object, form of index. This is accomplished using a primitive
- Xmethod, (the message \fBbasicAt:\fP is handled in a similar fashion in
- Xclass \fBObject\fP, only using a different primitive).
- X.DS I
- X\fBbasicAt:\fP index
- X \(ua <26 self index>
- X.DE
- X.PP
- XLike a byte array, a string can also store two byte values in the space
- Xit takes to store a single object pointer. Unlike a byte array, however,
- Xa string can be any length, not just an even length. Therefore the message
- X\fBsize\fP is redefned in class \fBString\fP, a subclass of \fBByteArray\fP.
- X.DS I
- X\fBsize\fP
- X \(ua <14 self>
- X.DE
- X.PP
- XAnother difference between a string and a byte array is that the value
- Xreturned by a string must be a character, not an integer. Therefore
- X\fBbasicAt:\fP must also be redefined. By using the message \fBbasicAt:\fP
- Xdefined in \fBByteArray\fP, (the superclass of String, and therefore accessible
- Xvia the pseudo variable \fBsuper\fP) the method can obtain the integer value
- Xof the appropriate character. This value is then used to create a new
- Xinstance of class \fBChar\fP:
- X.DS I
- X\fBbasicAt:\fP index
- X \(ua Char new; value: (super basicAt: index)
- X.DE
- X.PP
- XA value is placed into an array using the message \fPat:put:\fP. As with
- X\fBat:\fP, a value should only be placed if the index represents a legal
- Xsubscript. This is checked in the following method:
- X.DS I
- X\fBat:\fP index \fBput:\fP value
- X (self includesKey: index)
- X ifTrue: [ self basicAt: index put: value ]
- X ifFalse: [ smalltalk error:
- X 'illegal index to at:put: for array' ]
- X.DE
- X.PP
- XAs was the case with \fBbasicAt:\fP, one version of \fBbasicAt:put:\fP,
- Xto be used by arrays of objects, is defined as part of class \fBObject\fP.
- XA different version is found in class \fBByteArray\fP. Finally a third
- Xversion, which first checks to see if the argument is a Character, is found
- Xin class \fBString\fP.
- X.DS I
- X\fBat:\fP index \fBput:\fP aValue
- X (aValue isMemberOf: Char)
- X ifTrue: [ super basicAt: index put: aValue asciiValue ]
- X ifFalse: [ smalltalk error:
- X 'cannot put non Char into string' ]
- X.DE
- X.SH
- XExercises
- X.IP 1.
- XDescribe the sequence of messages used to respond to the following:
- X.DS B
- Xx \(<- #(1 2 3) at: 2
- X.DE
- X.IP 2.
- XDescribe how the execution of the above expression could be speeded up by
- Xadding new methods. Note if your methods are specific to arrays of objects,
- Xarrays of bytes, or strings.
- /
- echo 'x - general.ms'
- sed 's/^X//' > general.ms << '/'
- X.\" information on Little Smalltalk, version 2, beta release
- X.SH
- XGeneral Overview
- X.PP
- XFirst, the obvious facts. This is not Smalltalk-80, nor even Smalltalk-V.
- XThis is the second version of the Little Smalltalk system, the first version
- Xof which is described in the book recently published by Addison-Wesley*.
- X.FS
- X* \fIA Little Smalltalk\fP, by Timothy A. Budd. Published by Addison
- XWesley, 1987. In better bookshops everywhere.
- X.FE
- XVersion two is smaller and faster; does more in Smalltalk, less in C; and is
- Xdesigned to be more portable to a wider variety of machines (we are working
- Xon versions now for various PCs).
- X.PP
- XMy attitude towards the language has been
- Xrather cavalier; what I liked I kept and what I didn't like I tossed out.
- XThis is explained in more detail in my book and in the end of this note.
- XAs a consequence, individuals familiar with ST-80 or Smalltalk-V will be struck
- Xby how much they are missing, and I make no apologies for this. On the
- Xother hand, you don't find Smalltalk-V posted to comp.source.unix.
- XAmong the features
- Xyou won't find here are metaclasses, class methods, windows, graphics
- Xsupport, and more.
- X.PP
- XWhat you will find is a small language that does give you the flavor of
- Xobject oriented programming at very little cost. We are working to improve
- Xthe system, and hope to distribute new versions as we develop them,
- Xas well as porting it to a wide range of machines.
- XIf you find (and preferably, fix!) bugs let us know.
- XIf you make nice additions let us know.
- XIf you want to make complements let us know.
- XIf you want to make complaints let us know.
- XIf you want support you just might be out of luck.
- X.PP
- XThis software is entirely public domain. You are encouraged to give it
- Xto as many friends as you may have. As a courtesy, I would appreciate it
- Xif you left my name on the code as the author, but I make no other claims
- Xto it (I also, of course, disavow any liability for any bizarre things you
- Xmay choose to do with it). Enjoy.
- X.SH
- XBuilding the System
- X.PP
- XThe first step in building the system is to unpack the sources.
- XThe fact that you are reading this means you have probably already figured
- Xout how to do this.
- X.PP
- XThere are various different types of files sent with the distribution.
- XFiles ending in .c and .h are C sources, for both the parser and the bytecode
- Xinterpreter. Files ending in .ms are manuscripts, in troff format using
- Xthe ms macro package (this file is a good example). Files ending in .st
- Xare smalltalk sources, compiled by the parser to make the initial object
- Ximage. Finally, there are a few small files that don't fall into any
- Xcategory, BUGS for listing notable bugs, the make file, and so on.
- X.PP
- XThe next step is to tailor the system to the type of enviornment it will be
- Xrun in.
- XFor most users, this should mean only changing at most three lines in the
- Xfile env.h. These three lines are near the front of the file and are
- Xclearly marked. Two are hard paths; for the default initial object image
- Xand for a temporary file to be used when editing. The third line is a
- X``meta-define'' which indicates the type of machine and/or operating system
- Xto be used. You should examine the rest of the file to see the variety of
- Xsystems supported. If you are unable to find anything appropriate, you will
- Xhave to look in the document install.ms for further instructions. In this
- Xlatter case, if you are sucessful in porting the software to a new machine,
- XI would be pleased if you could let me know the nature of the changes
- Xrequired.
- X.PP
- XOnce you have tailored the system, there are then
- Xthree steps involving in building the system; making the parser
- X(the component used to generate the initial object image), making the
- Xbytecode interpreter, and making the object image. Typing \fImake\fP, with
- Xno arguments, will do all three. For more detailed instructions on making
- Xthe system consult install.ms.
- X.PP
- XOnce you have sucessfully created the parser, the bytecode compiler, and
- Xan object image, type
- X.DS I
- Xst
- X.DE
- X.LP
- Xto run the system.
- XNow would be a very good time to go read explore.ms, which would tell you
- Xmore how to find your way around.
- X.SH
- XChanges from Little Smalltalk version one
- X.PP
- XThe following changes have been made from version one to version two:
- X.IP \(bu
- XThe user interface is slightly different. This is most apparent in the way
- Xnew classes are added (see explore.ms), and in the fact that expressions will
- Xnot be printed unless you explicitly request printing, and in the fact that
- Xnew global variables cannot be created at the command level merely by
- Xassignment.
- X.IP \(bu
- XMuch (very much) more of the system is now written in Smalltalk, rather
- Xthan C. This allows the user to see, and modify it if they wish.
- XThis also means that the virtual machine is now much smaller.
- X.IP \(bu
- XThe pseudo variable selfProcess is no longer supported.
- XThe variables true, false and nil are now treated as global variables, not
- Xpseudo variables (see below).
- XThere are plans for adding processes to version two, but they have not
- Xbeen formalized yet.
- X.IP \(bu
- XGlobal variables are now supported; in fact classes are now simply global
- Xvariables, as are the variables true, false, smalltalk and nil.
- XThe global variable globalNames contains the dictionary of all currently
- Xknown global variables and their values.
- X(Pool variables are still not supported).
- X.IP \(bu
- XNumbers are a little more robust. If integer operations overflow, they are
- Xautomatically converted into floating point numbers. This is under control
- Xof Smalltalk code, so if I (or, preferably, somebody else) ever get around
- Xto implementing infinite precision numbers, they can easily be added in.
- X.IP \(bu
- XThe internal bytecodes are slightly different. In particular, the bytecode
- Xrepresenting ``send to super'' has been eliminated, and a bytecode representing
- X``do a primitive'' has been added.
- X.IP \(bu
- XThe internal representation of objects is different. Instead of the
- X``super-object'' chain, objects are now created big enough to hold all the
- Xinstance variables for all their superclasses. (This is the way it is done
- Xin Smalltalk-80, and, to the best of my knowledge, in Smalltalk-V).
- X.IP \(bu
- XThe Collection hierarchy has been rearranged. The rational for this change
- Xis explained in more detail in another essay.
- X(possibly not written yet).
- X.IP \(bu
- XSome methods, most notably the error message methods, have been moved out
- Xof class Object and into class Smalltalk.
- X.IP \(bu
- XThe syntax for primitives is different; the keyword \fBprimitive\fP has been
- Xeliminated, and named primitives are now gone as well.
- XFewer actions are performed by primitives, having been
- Xreplaced by Smalltalk methods.
- X.IP \(bu
- XCommand line options, such as the fast load feature, have been eliminated.
- XHowever, since version two reads in a binary object image, not a textual
- Xfile, loading should be considerably faster.
- X.SH
- XElectronic Communication
- X.PP
- XHere is my address, various net addresses:
- X.DS I
- XTim Budd
- XOregon State University
- XDepartment of Computer Science
- XCorvallis, Oregon 97331 USA
- X(503) 754-3273
- X
- Xbudd@ cs.orst.edu
- X
- X{tektronix, hp-pcd} !orstcs!budd
- X.DE
- X.SH
- XChanges
- X.PP
- XI want to emphasize that this is not even a beta-test version (does that
- Xmake it an alpha or a gamma version?). I will be making a number of
- Xchanges, hopefully just additions to the initial image, in the next
- Xfew months. In addition, I hope to prepare versions for other machines,
- Xnotably the Macintosh and the IBM PC. I am also encouraging others to
- Xport the system to new machines. If you have done so, please let me
- Xknow.
- /
- echo 'x - install.ms'
- sed 's/^X//' > install.ms << '/'
- X.SH
- XInstalling Little Smalltalk
- X.PP
- XFor most users the following simple steps should suffice to build the
- Xsystem.
- X.IP \(bu
- XUnpack the sources.
- X.IP \(bu
- XEdit the file env.h, changing the metadefine to an already known system
- Xtype.
- X.IP \(bu
- XType \fImake\fP.
- X.PP
- XThere are a few systems for which more extensive work is required;
- Xand of course porting the system to new environments may entail
- Xconsiderable work.
- XThe remainder of this document is intended to provide more detailed
- Xinformation for the curious, and to help those individuals for whom the
- Xprevious instructions don't work.
- X.SH
- XIBM PC and Turbo C
- X.PP
- XFor these systems there are two small changes that are required, in addition
- Xto those noted above. In the method for saveImage, class Smalltalk, file
- Xunix.c, the mode for the open statement must be 'wb', not 'w'.
- XAnd in method delete, class File, file unix.c, the command used to delete
- Xfiles should be ``DEL'', not ``rm''.
- XIt may also be necessary to redefine the value of the global variable
- X\fIeditor\fP (set by the script found in file script.ini, used when making
- Xthe initial image). Also the name of a temporary file (found in method
- XscratchFile, class File, file unix.st) may have to be changed.
- X.SH
- XTektronix 4404
- X.PP
- XThere are several changes that are required to get the system to run on the
- X4404. Start by defining the metadefine constant SYSV in env.h.
- XNext, change the Makefile in the following ways,
- X.IP \(bu
- XTranslate all the .o extensions to .r .
- X.IP \(bu
- XRemove any CFLAGS definitions.
- X.IP \(bu
- XChange the rules for parse and st to use +o= notation, which must appear at
- Xthe end. Also add a call on headset, setting the program size to at least
- X512K (more if you have it).
- X.DS I
- Xst: \fIfile names\fP
- X cc \fIfile names\fP +o=st
- X headset st +b=512K
- X.DE
- X.SH
- XPorting to new systems
- X.PP
- XThere are many ways in which compilers and operating systems differ
- Xfrom each other.
- XA fair amount of work has been expanded in making sure the software will
- Xoperate on most machines, which requires that different code fragements be
- Xused on different systems. In large part these are controlled by a single
- X``meta-define'' in the file env.h. Setting this one value then causes the
- Xexpansion of another code segment, which then defines many more options.
- X.PP
- XIn the event that you are attempting to port the software to a system that
- Xhas not previously been defined, you will need to decide which set of
- Xoptions to enable. The next two sections contain information you may need
- Xin making this determination.
- X.SH
- XDefine Options
- X.PP
- XMany options are specified merely by giving or not giving a DEFINE
- Xstatement in the file env.h. The following table presents the meaning for
- Xeach of these values:
- X.de Op
- X.IP \\fB\\$1\\fP
- X.br
- X..
- X.Op ALLOC
- XDefined If there is an include file called alloc.h which defines calloc,
- Xmalloc, and the like.
- X.Op BINREADWRITE
- XDefined if the fopen specification for binary files must include the "b"
- Xmodifier. This is true on many MS-DOS inspired systems.
- X.Op NOENUMS
- XDefined if enumerated datatypes are not supported. If defined, these will
- Xbe replaced by #define constants.
- X.Op NOTYPEDEF
- XDefined if the typedef construct is not supported. If defined, these will
- Xbe replaced by #define constructs.
- X.Op NOVOID
- XDefined if the void keyword is not recognized.
- XIf defined, expect \fIlint\fP to complain a lot about functions returning
- Xvalues which are sometimes (or always) ignored.
- X.Op SIGNALS
- XUsed if \fIboth\fP the <signals.h> package and the <longjmp.h> package are
- Xavilable, and if the routine used to set signals is signal.
- XIncompatible with \fBSSIGNALS\fP.
- X.Op SSIGNALS
- XUsed if \fIboth\fP the <signals.h> package and the <longjmp.h> package are
- Xavailable, and if the routine used to set signals is ssignal.
- XIncompatible with \fBSIGNALS\fP.
- X.Op STRING
- XUsed if the string functions (strcpy, strcat and the like) are found in
- X<string.h>. This switch is incompatible with \fBSTRINGS\fP.
- X.Op STRINGS
- XUsed if the string functions (strcpy, strcat and the like) are found in
- X<strings.h>. This switch is incompatible with \fBSTRING\fP.
- X.LP
- XIn addition, several routines can optionally be replaced by macros for
- Xgreater efficiency. See the file memory.h for more information.
- X.SH
- XObject Memory
- X.PP
- XThere are several datatypes, not directly supported by C, that are used in
- Xthe Little Smalltalk system. The first of these is the datatype byte.
- XA byte is an eight bit unsigned (hence positive) quantity.
- XOn many systems the appropriate datatype is unsigned char, however on other
- Xsystems this declaration is not recognized and other forms may be required.
- XTo aid in coverting to and from bytes the macro byteToInt() is used, which
- Xconverts a byte value into an integer. In addition, the routines byteAt
- Xand byteAtPut are used to get and put bytes from byte strings.
- X.PP
- XThe other datatype is that used to represent object points. On most
- Xmachines in which a short is 16 bits, the datatype short should suffice.
- XMuch more information on the memory module can be found in the file
- Xmemory.h.
- X.SH
- XOptions in Building the System
- X.PP
- XTo create the parser type
- X.DS I
- Xmake parse
- X.DE
- X.PP
- XThe resulting program, called parse, is used to generate the object image
- Xinitially loaded into the bytecode interpreter.
- X.PP
- XNext, make the interpreter itself by typing
- X.DS I
- Xmake st
- X.DE
- X.PP
- XNote that the interpreter and the parser share some files.
- X.PP
- XFinally, produce an initial object image. The image created when you type
- X.DS I
- Xmake sunix
- X.DE
- X.LP
- Xis the smallest and fastest. It is a single process version of smalltalk.
- XA slower multiprocess version can be created by typing ``make munix''*.
- X.FS
- X* Multi processing from munix is done entirely in Smalltalk.
- XWhile this is a good idea from the point of view of keeping the bytecode
- Xinterpreter small and giving one the greatest flexibility, there seems to
- Xbe a dramatic performance penalty. I'm considering the alternatives.
- X.FE
- XOf more interest, an image containing test cases
- Xcan be generated by typing ``make stest''.
- XThis command compiles several test cases, then runs st on a script which
- Xinvokes all the test cases. There is a similar command mtest for the
- Xmultiprocessing version.
- X.PP
- XOnce you have created an object image, type
- X.DS I
- Xst
- X.DE
- X.LP
- Xto run the system.
- XBy default the image file ``imageFile'' is read. You can optionally
- Xuse a different image file by giving the name on the command line following
- Xthe st command.
- X.SH
- XCompiler Bogosities
- X.PP
- XThis section will detail some of the unnatural actions you may have to
- Xperform to get Little Smalltalk to work with a few brain damaged compilers.
- XSince there are so few of these, it I see it as a problem more with the
- Xcompilers than with the system, the code make no accomodation for these.
- X.PP
- XOn some older Sequent Balance C compilers, incorrect code is produced for
- X.DS I
- Xhash %= (objectSize(symbols) / 2)
- X.DE
- X.LP
- XIn the file image.c. This should be replaced by
- X.DS I
- Xhash = hash % (objectSize(symbols) / 2)
- X.DE
- X.PP
- XOn many systems external names are restricted to six (or even five!)
- Xcharacters. This causes significant problems. I have heard of systems
- Xwhich automatically generate a sed script to take care of this, but have
- Xnot found one yet. If you know of such a thing let me know.
- X.SH
- XHelping Others
- X.PP
- XIf you succeed in getting Little Smalltalk ported to a machine or operating
- Xsystem not described in env.h, I would be most pleased to get a listing of
- Xthe changes you made. These can then be incorporated into the latest
- Xdistribution.
- /
- echo 'x - lex.c'
- sed 's/^X//' > lex.c << '/'
- X/*
- X Little Smalltalk, version 2
- X Written by Tim Budd, Oregon State University, July 1987
- X
- X lexical analysis routines for method parser
- X should be called only by parser
- X*/
- X
- X# include <stdio.h>
- X# include <ctype.h>
- X# include "env.h"
- X# include "memory.h"
- X# include "lex.h"
- X
- Xextern double atof();
- X
- X/* global variables returned by lexical analyser */
- X
- Xtokentype token; /* token variety */
- Xchar tokenString[80]; /* text of current token */
- Xint tokenInteger; /* integer (or character) value of token */
- Xdouble tokenFloat; /* floating point value of token */
- X
- X/* local variables used only by lexical analyser */
- X
- Xstatic char *cp; /* character pointer */
- Xstatic char pushBuffer[10]; /* pushed back buffer */
- Xstatic int pushindex; /* index of last pushed back char */
- Xstatic char cc; /* current character */
- Xstatic long longresult; /* value used when building int tokens */
- X
- X/* lexinit - initialize the lexical analysis routines */
- Xnoreturn lexinit(str)
- Xchar *str;
- X{
- X pushindex = 0;
- X cp = str;
- X /* get first token */
- X ignore nextToken();
- X}
- X
- X/* pushBack - push one character back into the input */
- Xstatic pushBack(c)
- Xchar c;
- X{
- X pushBuffer[pushindex++] = c;
- X}
- X
- X/* nextChar - retrieve the next char, from buffer or input */
- Xstatic char nextChar()
- X{
- X if (pushindex > 0) cc = pushBuffer[--pushindex];
- X else if (*cp) cc = *cp++;
- X else cc = '\0';
- X return(cc);
- X}
- X
- X/* isClosing - characters which can close an expression */
- Xstatic boolean isClosing(c)
- Xchar c;
- X{
- X switch(c) {
- X case '.': case ']': case ')': case ';':
- X return(true);
- X }
- X return(false);
- X}
- X
- X/* isSymbolChar - characters which can be part of symbols */
- Xstatic boolean isSymbolChar(c)
- Xchar c;
- X{
- X if (isdigit(c) || isalpha(c)) return(true);
- X if (isspace(c) || isClosing(c)) return(false);
- X return(true);
- X}
- X
- X/* singleBinary - binary characters that cannot be continued */
- Xstatic boolean singleBinary(c)
- Xchar c;
- X{
- X switch(c) {
- X case '[': case '(': case ')': case ']':
- X return(true);
- X }
- X return(false);
- X}
- X
- X/* binarySecond - return true if char can be second char in binary symbol */
- Xstatic boolean binarySecond(c)
- Xchar c;
- X{
- X if (isalpha(c) || isdigit(c) || isspace(c) || isClosing(c) ||
- X singleBinary(c))
- X return(false);
- X return(true);
- X}
- X
- Xtokentype nextToken()
- X{ char *tp;
- X boolean sign;
- X
- X /* skip over blanks and comments */
- X while(nextChar() && (isspace(cc) || (cc == '"')))
- X if (cc == '"') {
- X /* read comment */
- X while (nextChar() && (cc != '"')) ;
- X if (! cc) break; /* break if we run into eof */
- X }
- X
- X tp = tokenString;
- X *tp++ = cc;
- X
- X if (! cc) /* end of input */
- X token = inputend;
- X
- X else if (isalpha(cc)) { /* identifier */
- X while (nextChar() && isalnum(cc))
- X *tp++ = cc;
- X if (cc == ':') {
- X *tp++ = cc;
- X token = namecolon;
- X }
- X else {
- X pushBack(cc);
- X token = nameconst;
- X }
- X }
- X
- X else if (isdigit(cc)) { /* number */
- X longresult = cc - '0';
- X while (nextChar() && isdigit(cc)) {
- X *tp++ = cc;
- X longresult = (longresult * 10) + (cc - '0');
- X }
- X if (longCanBeInt(longresult)) {
- X tokenInteger = longresult;
- X token = intconst;
- X }
- X else {
- X token = floatconst;
- X tokenFloat = (double) longresult;
- X }
- X if (cc == '.') { /* possible float */
- X if (nextChar() && isdigit(cc)) {
- X *tp++ = '.';
- X do
- X *tp++ = cc;
- X while (nextChar() && isdigit(cc));
- X if (cc) pushBack(cc);
- X token = floatconst;
- X *tp = '\0';
- X tokenFloat = atof(tokenString);
- X }
- X else {
- X /* nope, just an ordinary period */
- X if (cc) pushBack(cc);
- X pushBack('.');
- X }
- X }
- X else
- X pushBack(cc);
- X
- X if (nextChar() && cc == 'e') { /* possible float */
- X if (nextChar() && cc == '-') {
- X sign = true;
- X ignore nextChar();
- X }
- X else
- X sign = false;
- X if (cc && isdigit(cc)) { /* yep, its a float */
- X *tp++ = 'e';
- X if (sign) *tp++ = '-';
- X while (cc && isdigit(cc)) {
- X *tp++ = cc;
- X ignore nextChar();
- X }
- X if (cc) pushBack(cc);
- X *tp = '\0';
- X token = floatconst;
- X tokenFloat = atof(tokenString);
- X }
- X else { /* nope, wrong again */
- X if (cc) pushBack(cc);
- X if (sign) pushBack('-');
- X pushBack('e');
- X }
- X }
- X else
- X if (cc) pushBack(cc);
- X }
- X
- X else if (cc == '$') { /* character constant */
- X tokenInteger = (int) nextChar();
- X token = charconst;
- X }
- X
- X else if (cc == '#') { /* symbol */
- X tp--; /* erase pound sign */
- X if (nextChar() == '(')
- X token = arraybegin;
- X else {
- X pushBack(cc);
- X while (nextChar() && isSymbolChar(cc))
- X *tp++ = cc;
- X pushBack(cc);
- X token = symconst;
- X }
- X }
- X
- X else if (cc == '\'') { /* string constant */
- X tp--; /* erase pound sign */
- X strloop:
- X while (nextChar() && (cc != '\''))
- X *tp++ = cc;
- X /* check for nested quote marks */
- X if (cc && nextChar() && (cc == '\'')) {
- X *tp++ = cc;
- X goto strloop;
- X }
- X pushBack(cc);
- X token = strconst;
- X }
- X
- X else if (isClosing(cc)) /* closing expressions */
- X token = closing;
- X
- X else if (singleBinary(cc)) { /* single binary expressions */
- X token = binary;
- X }
- X
- X else { /* anything else is binary */
- X if (nextChar() && binarySecond(cc))
- X *tp++ = cc;
- X else
- X pushBack(cc);
- X token = binary;
- X }
- X
- X *tp = '\0';
- X return(token);
- X}
- /
- echo 'x - names.c'
- sed 's/^X//' > names.c << '/'
- X/*
- X Little Smalltalk, version 2
- X Written by Tim Budd, Oregon State University, July 1987
- X
- X Name Table module
- X
- X A name table is the term used for a Dictionary indexed by symbols.
- X There are two name tables used internally by the bytecode interpreter.
- X The first is the table, contained in the variable globalNames,
- X that contains the names and values of all globally accessible
- X identifiers. The second is the table of methods associated with
- X every class. Notice that in neither of these cases does the
- X system ever put anything INTO the tables, thus there are only
- X routines here for reading FROM tables.
- X
- X (putting things INTO the table is all done in Smalltalk code,
- X using the methods from class Dictionary)
- X
- X One complication of instances of class Symbol is that all
- X symbols must be unique, not only so that == will work as expected,
- X but so that memory does not get overly clogged up with symbols.
- X Thus all symbols are kept in a hash table, and when new symbols
- X are created (via newSymbol(), below) they are inserted into this
- X table, if not already there.
- X
- X This module also manages the definition of various symbols that are
- X given fixed values for efficiency sake. These include the objects
- X nil, true, false, and various classes.
- X*/
- X
- X# include <stdio.h>
- X# include "env.h"
- X# include "memory.h"
- X# include "names.h"
- X
- X/* global variables used to avoid repeated examinations of the global symbol table */
- Xobject trueobj = nilobj; /* the pseudo variable true */
- Xobject falseobj = nilobj; /* the pseudo variable false */
- Xobject smallobj = nilobj; /* the pseudo variable smalltalk */
- Xobject arrayclass = nilobj; /* the class ``Array'' */
- Xobject blockclass = nilobj; /* the class ``Block'' */
- Xobject contextclass = nilobj; /* the class ``Context'' */
- Xobject intclass = nilobj; /* the class ``Integer'' */
- Xobject intrclass = nilobj; /* the class ``Interpreter'' */
- Xobject symbolclass = nilobj; /* the class ``Symbol'' */
- Xobject stringclass = nilobj; /* the class ``String'' */
- X
- X/*
- X some messages are encoded in concise bytecode format -
- Xto reduce the size of the compiled methods
- X(also, in some cases, to more efficiently detect special cases
- Xhandled in the interpreter, rather than by methods)
- X*/
- X
- Xchar *binStrs[] = {"+", "-", "<", ">", "<=", ">=", "=", "~=", "*",
- X"quo:", "rem:", "bitAnd:", "bitXor:",
- X"==", ",", "at:", "basicAt:", "do:", "coerce:", "error:", "includesKey:",
- X"isMemberOf:", "new:", "to:", "value:", "whileTrue:", "addFirst:", "addLast:",
- X0};
- X
- Xobject binSyms[28];
- X
- Xchar *unStrs[] = {"isNil", "notNil", "new", "value", "class", "size",
- X"basicSize", "print", "printString", 0};
- X
- Xobject unSyms[9];
- X
- Xchar *keyStrs[] = {"at:ifAbsent:", "at:put:", "basicAt:put:", "between:and:",
- X0};
- X
- Xobject keySyms[4];
- X
- Xobject nameTableLookup(dict, symbol)
- Xobject dict, symbol;
- X{ int hash, tablesize;
- X object table, link;
- X
- X /* first get hash table */
- X table = basicAt(dict, 1);
- X
- X /* now see if table is valid */
- X if ((tablesize = objectSize(table)) < 3)
- X sysError("system error","lookup on null table");
- X else {
- X hash = 3 * ( symbol % (tablesize / 3));
- X if (basicAt(table, hash+1) == symbol)
- X return(basicAt(table, hash+2));
- X
- X /* otherwise look along the chain of links */
- X for (link=basicAt(table, hash+3); link != nilobj;
- X link=basicAt(link, 3))
- X if (basicAt(link, 1) == symbol)
- X return(basicAt(link, 2));
- X
- X }
- X return (nilobj);
- X}
- X
- Xobject getClass(obj)
- Xobject obj;
- X{
- X if (isInteger(obj))
- X return(intclass);
- X return (classField(obj));
- X}
- X
- Xstatic object globalGet(name)
- Xchar *name;
- X{ object newobj;
- X
- X newobj = globalSymbol(name);
- X if (newobj == nilobj)
- X sysError("symbol not found in image", name);
- X return(newobj);
- X}
- X
- Xnoreturn initCommonSymbols()
- X{ int i;
- X
- X trueobj = globalGet("true");
- X falseobj = globalGet("false");
- X smallobj = globalGet("smalltalk");
- X arrayclass = globalGet("Array");
- X blockclass = globalGet("Block");
- X contextclass = globalGet("Context");
- X intclass = globalGet("Integer");
- X symbolclass = globalGet("Symbol");
- X stringclass = globalGet("String");
- X /* interpreter may or may not be there */
- X intrclass = globalSymbol("Interpreter");
- X
- X for (i = 0; i < 28; i++)
- X binSyms[i] = newSymbol(binStrs[i]);
- X
- X for (i = 0; i < 9; i++)
- X unSyms[i] = newSymbol(unStrs[i]);
- X
- X for (i = 0; i < 4; i++)
- X keySyms[i] = newSymbol(keyStrs[i]);
- X}
- X
- Xobject newArray(size)
- Xint size;
- X{ object newobj;
- X
- X if (arrayclass == nilobj) {
- X arrayclass = globalSymbol("Array");
- X if (arrayclass == nilobj)
- X sysError("can't find global symbol","Array");
- X }
- X newobj = allocObject(size);
- X setClass(newobj, arrayclass);
- X return(newobj);
- X}
- X
- Xobject newSymbol(str)
- Xchar *str;
- X{ int hash;
- X object newSym, link;
- X char *p;
- X
- X /* first compute hash value of string text */
- X /* this is duplicated in image.c - make sure any changes match there */
- X hash = 0;
- X for (p = str; *p; p++)
- X hash += *p;
- X if (hash < 0) hash = - hash;
- X hash = 2 * ( hash % (objectSize(symbols) / 2));
- X
- X /* next look to see if it is in symbols - note that this
- X text duplicates that found in nameTableLookup, only using
- X string comparison instead of symbol comparison */
- X newSym = basicAt(symbols, hash+1);
- X if (newSym && streq(str, charPtr(newSym)))
- X return(newSym);
- X
- X /* not in table, look along links */
- X for (link=basicAt(symbols, hash+2); link != nilobj; link=basicAt(link,2)) {
- X newSym = basicAt(link, 1);
- X if (streq(str, charPtr(newSym)))
- X return(newSym);
- X }
- X
- X /* not found, make a new symbol */
- X newSym = allocSymbol(str);
- X setClass(newSym, symbolclass);
- X
- X /* now insert new symbol in table, so next time we will find it */
- X if (basicAt(symbols, hash+1) == nilobj)
- X basicAtPut(symbols, hash+1, newSym);
- X else { /* insert along links */
- X link = allocObject(2);
- X basicAtPut(link, 1, newSym);
- X basicAtPut(link, 2, basicAt(symbols, hash+2));
- X basicAtPut(symbols, hash+2, link);
- X }
- X
- X return(newSym);
- X}
- X
- Xobject newStString(value)
- Xchar *value;
- X{ object newobj;
- X
- X newobj = allocSymbol(value);
- X setClass(newobj, stringclass);
- X return(newobj);
- X}
- X
- Xobject newFloat(d)
- Xdouble d;
- X{ object newobj;
- X
- X newobj = allocFloat(d);
- X setClass(newobj, globalSymbol("Float"));
- X return(newobj);
- X}
- /
- echo 'x - todo'
- sed 's/^X//' > todo << '/'
- XThings to do
- X
- XWrite infinite precision number package.
- X
- XAdd traceback (unfortunately, this must be done in the interpreter, not
- Xin Smalltalk code).
- X
- XAdd descriptions to classes (to be displayed by display)
- X
- Xflush message cache shouldn't flush everything, just one entry.
- X
- Xchange process manager to use alloca, if available (this would allow
- Xprocesses to run as deep as the process stack, instead of the artificial
- Xlimitation now imposed).
- X
- Xadd methods to class Class so that assigning variables: or changing
- Xsuperclass will automatically recompile all methods.
- X
- XMake files a subclass of collection (to be useful, requires adding more
- Xfunctionality to files).
- X
- Xmodify the parser so that it can add to an existing image.
- X
- XDone
- X
- XClass File now added, changes interface to use files.
- XInteger arith ops now trap overflows
- XAllowed non-alpha tokens (such as #+ )
- XFixed doEdit so that it allows you to retry.
- XFixed parser so that optimized messages don't require [ ] around args.
- XFixed parser so that empty blocks work correctly
- XTraps interrups and restarts gracefully now.
- XCreated much better user interface
- XFixed bug in lexer, preventing reading past end of input
- X
- Xmessages added:
- X display (for classes and collections)
- X respondsTo (for symbols)
- X changed indexOf to take a block, rather than a value
- X class addSubClass
- X smalltalk inquire:
- /
- echo 'x - top.ms'
- sed 's/^X//' > top.ms << '/'
- X.SH
- XWho's On Top?
- X.PP
- XOne of the most important decisions to be made in designing a new user
- Xinterface (or front end) for the Little Smalltalk system is whether the user
- Xinterface management code should sit on top of the Smalltalk bytecode
- Xinterpreter, setting up commands and invoking the interpreter to execute them,
- Xor underneith the bytecode interpreter, being invoked by Smalltalk, via the
- Xmechanism of primitive methods. Both schemes have advantages and disadvantages
- Xwhich we will discuss in this essay.
- X.PP
- XIn a simple interface, placing Smalltalk on top is often easier. The main
- Xdriver need only set up one initial call to the Smalltalk bytecode interpreter,
- Xand thereafter everything is done in Smalltalk. For example, we might put
- Xinitialization code in a method in class \fBSmalltalk\fP, as follows:
- X.DS L
- XClass Smalltalk
- X getString
- X \(ua <1>
- X|
- X run | string |
- X [ '> ' printNoReturn.
- X string <- smalltalk getString.
- X string notNil ]
- X whileTrue: [ (string size > 0)
- X ifTrue: [ smalltalk doIt: string ] ]
- X]
- X.DE
- X.PP
- XOnce the bytecode interpreter is started on the method \fBrun\fP, it will
- Xloop continuously, reading commands from the user (via the method
- X\fBgetString\fP) and executing them (via the method \fBdoIt:\fP).
- XPresumably the user has some way of indicating end of input, such as the
- Xunix control-D convention, which causes \fBgetString\fP to return the
- Xvalue nil. The \fIif\fP statement inside the while loop
- Xinsures that if the user simply hits the return key execution will quickly
- Xloop back to the prompt.
- X.PP
- XBesides making the initialization for the Little Smalltalk system easy,
- Xthis approach also has the advantage of putting more code into Smalltalk
- Xitself, where the user can see it and (presumably) modify it if they wish.
- XA general guideline is that it is better to put as much into Smalltalk
- Xas possible, since Smalltalk is easier to write and the bytecode representation
- Xusually smaller than the equivalent code in C.
- XNever the less, there are valid reasons why an implementor might choose
- Xa different technique.
- X.PP
- XFor example, if there are many other activities which should command the
- Xattention of the controlling program (window updates, mouse motions) the
- XSmalltalk code may not be able to respond fast enough, or might become too
- Xlarge and complex to be workable.
- XIn this case the only alternative is to have the front end respond directly
- Xto events, and only invoke the Smalltalk interpreter as time permits.
- XIn basic terms, the front end would perform the loop written in the method
- X\fBinit\fP shown above (along with handling various other tasks), and then
- Xcall upon the method in class \fBSmalltalk\fP
- Xto execute the message \fBdoIt:\fP.
- X.SH
- XHow to Do It
- X.PP
- XIn either of the two schemes described above, an important message is
- X\fBdoIt:\fP, which takes a string (presumably representing a Smalltalk
- Xexpression) and performs it. An easy way to perform this message is to
- Xmake a method out of the expression, by appending a message pattern
- Xon front, and then pass the string to the method parser. If the method
- Xparser is successful, the method can then be executed.
- X.DS L
- XdoIt: aString | method |
- X method <- Method new.
- X method text: ( 'proceed ', aString ).
- X (method compileWithClass: Smalltalk)
- X ifTrue: [ method executeWith: #( 0 ) ]
- X.DE
- X.PP
- XThe message \fBcompileWithClass:\fP compiles the method as if it was
- Xappearing as part of class Smalltalk. If compilation is successful,
- Xthe message \fBexecuteWith:\fP executes the message, using as arguments
- Xthe array #(0). The array that accompanies this message must have at
- Xleast one element, as the first value is used as the receiver for
- Xthe method.
- XSimilar techniques can be used for the message \fBprintIt:\fP, if desired.
- X.SH
- XThe Other End
- X.PP
- XThe opposite extreme from the front end are those messages that originate
- Xwithin the bytecode interpreter and must be communicated to the user.
- XWe can divide these values into four categories:
- X.IP 1.
- XSystem errors. These are all funnelled through the routine sysError(), found
- Xin memory.c. System errors are caused by dramatically wrong conditions,
- Xand should generally cause the system to abort after printing the message
- Xpassed as argument to sysError().
- X.IP 2.
- XCompiler errors. As we noted above, the method compiler is used to
- Xparse expressions typed directly at the keyboard, so these message can
- Xalso arise in that manner. These are all funnelled through the routine
- XcompilError(), found in parse.c. These should print their arguments
- X(two strings), in an appropriate location on the users screen.
- XExecution continues normally after call.
- X.IP 3.
- XVarious primitives, found in primitive.c, are also used to print strings
- Xon the users terminal. In particular, an appropriate meaning should be
- Xgiven to the message \fBprint\fP in class \fBString\fP. What appropriate
- Xmeans is undoubtedly implementation specific.
- X.IP 4.
- XFinally, and perhaps most importantly, there must be some means provided
- Xto allow users to enter and edit methods. The interface for this task
- Xis standard; instances of class \fBClass\fP must respond to the messages
- X\fBaddMethod\fP and \fBeditMethod:\fP, the latter taking as argument a
- Xsymbol representing the name of a method. How they achieve their two
- Xtasks is, however, implementation specific.
- XUnder Unix, a simple implementation adds a new primitive for Strings;
- Xthis primitive copies the string into a temporary file, starts up the
- Xeditor on the file, and returns the contents of the file when the user
- Xexits the editor. Having this capability, the method editing code
- Xcan be given as follows. In class \fBClass\fP:
- X.DS L
- X addMethod
- X self doEdit: ''
- X|
- X editMethod: name | theMethod |
- X theMethod <- methods at: name
- X ifAbsent: [ 'no such method ' print. \(ua nil ].
- X self doEdit: theMethod text
- X|
- X doEdit: startingText | theMethod |
- X theMethod <- Method new;
- X text: startingText edit.
- X (theMethod compileWithClass: self)
- X ifTrue: [ methods at: theMethod name put: theMethod ]
- X.DE
- X.LP
- XAnd in class \fBString\fP:
- X.DS L
- X edit
- X \(ua <19 self>
- X.DE
- X.LP
- XHere primitive 19 performs all the tasks of creating the temporary file,
- Xstarting the editor, and creating the string representing the file
- Xcontents when the editor is exited.
- X.PP
- XAlternative techniques, for example using windowing, would undoubtedly
- Xbe more complicated.
- /
- echo 'x - unix.st'
- sed 's/^X//' > unix.st << '/'
- X*
- X* Little Smalltalk, version 2
- X* Written by Tim Budd, Oregon State University, July 1987
- X*
- X* methods for the unix front end - single process version
- X*
- X* (override previous declaration, adding new instance variable)
- XDeclare Smalltalk Object errorRecoveryBlock
- XDeclare File Object name pointer
- X* (better override global variable as well )
- XInstance Smalltalk smalltalk
- X* make global variables for standard files
- XInstance File stdin
- XInstance File stdout
- XInstance File stderr
- X*
- XClass File
- X asString | text line |
- X text <- ''.
- X [line <- self getString. line notNil]
- X whileTrue: [ text <- text , line ].
- X ^ text
- X|
- X name: string
- X name <- string
- X|
- X name
- X ^ name
- X|
- X scratchFile
- X name <- 'junk.tmp'
- X|
- X open: mode
- X pointer <- <120 name mode>.
- X pointer isNil
- X ifTrue: [ smalltalk error: 'open failed']
- X|
- X close
- X (pointer notNil)
- X ifTrue: [<121 pointer>].
- X pointer <- nil.
- X|
- X delete
- X ('rm ', name) unixCommand
- X|
- X fileIn | line |
- X [ line <- self getString. line notNil ]
- X whileTrue: [ line <- line words:
- X [:x | x isAlphabetic ] .
- X Switch new; key: (line at: 1);
- X ifMatch: 'Class' do: [self fileInClass: line ] ;
- X ifMatch: 'Method' do:
- X [ self fileInMethod: line ] ;
- X else: [ ^ smalltalk error:
- X 'invalid format for fileIn'] ]
- X|
- X fileInClass: commandLine | name |
- X name <- (commandLine at: 2
- X ifAbsent: [^ smalltalk error:
- X 'missing class name in Class directive'])
- X asSymbol.
- X globalNames at: name put: ( Class new;
- X name: name;
- X superClass: (globalNames at: (
- X commandLine at: 3
- X ifAbsent: [ ^ smalltalk error:
- X 'missing superclass name'])
- X asSymbol
- X ifAbsent: [ ^ smalltalk error:
- X 'unknown class']);
- X variables: (commandLine copyFrom: 4 to:
- X commandLine size ) )
- X|
- X fileInMethod: commandLine
- X (commandLine size ~= 2)
- X ifTrue: [ ^ smalltalk error:
- X 'invalid Method command line '].
- X (globalNames at: (commandLine at: 2) asSymbol
- X ifAbsent: [ ^ smalltalk error:
- X 'unknown class in Method header'])
- X fileInMethod: self
- X|
- X getString
- X ^ (pointer notNil)
- X ifTrue: [<125 pointer>]
- X|
- X getPrompt: aString
- X stdout printNoReturn: aString.
- X ^ self getString
- X|
- X inquire: aString | response |
- X response <- self getPrompt: aString.
- X response isNil
- X ifTrue: [ ^ false ].
- X ^ 'yY' includes: (response at: 1 ifAbsent: [])
- X|
- X print: aString
- X (pointer notNil)
- X ifTrue: [<129 pointer aString>]
- X ifFalse: [smalltalk error: 'file not open']
- X|
- X printNoReturn: aString
- X (pointer notNil)
- X ifTrue: [<128 pointer aString>]
- X ifFalse: [smalltalk error: 'file not open']
- X|
- X readUntil: conditionBlock doing: actionBlock | line |
- X [ line <- self getString. line notNil]
- X whileTrue: [ (conditionBlock value: line)
- X ifTrue: [ ^ line ].
- X actionBlock value: line ].
- X ^ nil
- X|
- X saveImage
- X (pointer notNil)
- X ifTrue: [<127 pointer>]
- X ifFalse: [smalltalk error: 'file not open']
- X]
- XClass Method
- X executeWith: arguments
- X ^ ( Context new ; method: self ;
- X temporaries: ( Array new: temporarySize) ;
- X arguments: arguments )
- X executeFrom: 0 creator: nil
- X]
- XClass Class
- X addMethod
- X self doEdit: ''
- X|
- X addSubClass | name |
- X name <- (stdin getPrompt: 'Class Name? ') asSymbol.
- X globalNames at: name put:
- X ( Class new; name: name ; superClass: self ;
- X readInstanceVariables; readMethods )
- X|
- X addMethodText: text | theMethod |
- X theMethod <- Method new; text: text.
- X (theMethod compileWithClass: self)
- X ifTrue: [ methods at: theMethod name put: theMethod.
- X smalltalk flushMessageCache.
- X ^ true ].
- X ^ false
- X|
- X doEdit: startingText | text |
- X text <- startingText.
- X [ text <- text edit.
- X (self addMethodText: text)
- X ifTrue: [ false ]
- X ifFalse: [ stdin inquire: 'edit again (yn) ? ' ]
- X ] whileTrue
- X|
- X display
- X ('Class name: ', name asString) print.
- X (superClass notNil)
- X ifTrue: [ ('Superclass: ', superClass ) print ].
- X 'Instance Variables:' print.
- X variables isNil
- X ifTrue: [ 'no instance variables ' print ]
- X ifFalse: [ variables display ].
- X 'Subclasses: ' print.
- X self subClasses display
- X|
- X editMethod: name
- X self doEdit: ( methods at: name
- X ifAbsent: [ 'no such method ' print. ^ nil ] ) text
- X|
- X fileInMethod: file | text line |
- X text <- ''.
- X line <- file readUntil: [:x | '|[' includes:
- X (x at: 1 ifAbsent: [] ) ]
- X doing: [:x | text <- text , x].
- X self addMethodText: text.
- X ^ line
- X|
- X fileOut: file
- X file printNoReturn: 'Class ', name asString.
- X file printNoReturn: ' ', superClass name asString.
- X variables do: [:x | file printNoReturn: ' ', x ].
- X file print: ''.
- X methods do: [:x | self fileOutMethod: x name to: file ]
- X|
- X fileOutMethod: method to: file
- X file print: 'Method ', name asString.
- X file print: (methods at: method
- X ifAbsent: [^ smalltalk error:
- X 'no such method' ]) text.
- X file print: '|'
- X|
- X readInstanceVariables
- X self variables:
- X ((stdin getPrompt: 'Instance Variables? ')
- X words: [:x | x isAlphabetic ])
- X|
- X readMethods
- X [ stdin inquire: 'Add a method (yn) ? ' ]
- X whileTrue: [ self addMethod ]
- X|
- X viewMethod: name
- X (methods at: name
- X ifAbsent: [ 'no such method ' print. ^ nil ]) text print
- X]
- XClass Smalltalk
- X error: aString
- X stderr print: 'Error: ',aString.
- X errorRecoveryBlock value
- X|
- X openFiles
- X stdin name: 'stdin'.
- X stdin open: 'r'.
- X stdout name: 'stdout'.
- X stdout open: 'w'.
- X stderr name: 'stderr'.
- X stderr open: 'w'.
- X|
- X commandLoop | string |
- X self openFiles.
- X [ string <- stdin getPrompt: '> '. string notNil ]
- X whileTrue: [ (string size strictlyPositive)
- X ifTrue: [ self doIt: string ] ]
- X|
- X doIt: aString | method |
- X errorRecoveryBlock <- [ ^ nil ].
- X method <- Method new.
- X method text: ( 'proceed ', aString ).
- X (method compileWithClass: Object)
- X ifTrue: [ method executeWith: #( 1 ) ]
- X|
- X saveImage | name |
- X name <- stdin getPrompt: 'type image name: '.
- X File new;
- X name: name;
- X open: 'w';
- X saveImage;
- X close.
- X ('image ', name, ' created') print
- X]
- XClass String
- X edit | file text |
- X file <- File new;
- X scratchFile;
- X open: 'w';
- X print: self;
- X close.
- X (editor, ' ', file name) unixCommand.
- X file open: 'r'.
- X text <- file asString.
- X file close; delete.
- X ^ text
- X|
- X print
- X ^ stdout print: self
- X|
- X unixCommand
- X ^ <88 self>
- X]
- /
- echo 'Part 04 of small.v2 complete.'
- exit
-