home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
116.lha
/
SmallTalk
/
Sources
/
image.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-11-20
|
9KB
|
333 lines
/*
Little Smalltalk, version 2
Written by Tim Budd, Oregon State University, July 1987
routines used in the making of the initial object image
*/
# include <stdio.h>
# include "env.h"
# include "memory.h"
# include "names.h"
# include "lex.h"
# ifdef STRING
# include <string.h>
# endif
# ifdef STRINGS
# include <strings.h>
# endif
# define SymbolTableSize 71
# define GlobalNameTableSize 53
# define MethodTableSize 39
# define globalNameSet(sym, value) nameTableInsert(globalNames, sym, value)
/*
the following classes are used repeately, so we put them in globals.
*/
static object ObjectClass;
static object ClassClass;
static object LinkClass;
static object DictionaryClass;
static object ArrayClass;
/*
we read the input a line at a time, putting lines into the following
buffer. In addition, all methods must also fit into this buffer.
*/
# define TextBufferSize 1024
static char textBuffer[TextBufferSize];
/*
nameTableInsert is used to insert a symbol into a name table.
see names.c for futher information on name tables
*/
nameTableInsert(dict, symbol, value)
object dict, symbol, value;
{ object table, link, newLink, nextLink, tablentry;
int hash;
#ifdef AMIGA
int temptablesize;
#endif
/* first get the hash table */
table = basicAt(dict, 1);
#ifdef AMIGA
temptablesize = objectSize(table);
if (temptablesize < 3)
#else
if (objectSize(table) < 3)
#endif
sysError("attempt to insert into","too small name table");
else {
hash = 3 * ( symbol % (objectSize(table) / 3));
tablentry = basicAt(table, hash+1);
if ((tablentry == nilobj) || (tablentry == symbol)) {
basicAtPut(table, hash+1, symbol);
basicAtPut(table, hash+2, value);
}
else {
newLink = allocObject(3);
incr(newLink);
setClass(newLink, globalSymbol("Link"));
basicAtPut(newLink, 1, symbol);
basicAtPut(newLink, 2, value);
link = basicAt(table, hash+3);
if (link == nilobj)
basicAtPut(table, hash+3, newLink);
else
while(1)
if (basicAt(link,1) == symbol) {
basicAtPut(link, 2, value);
break;
}
else if ((nextLink = basicAt(link, 3)) == nilobj) {
basicAtPut(link, 3, newLink);
break;
}
else
link = nextLink;
decr(newLink);
}
}
}
/*
there is sort of a chicken and egg problem about building the
first classes.
in order to do it, you need symbols,
but in order to make symbols, you need the class Symbol.
the routines makeClass and buildInitialNameTable attempt to get
carefully get around this initialization problem
*/
static object makeClass(name)
char *name;
{ object theClass, theSymbol;
/* this can only be called once newSymbol works properly */
theClass = allocObject(classSize);
theSymbol = newSymbol(name);
basicAtPut(theClass, nameInClass, theSymbol);
globalNameSet(theSymbol, theClass);
setClass(theClass, ClassClass);
return(theClass);
}
buildInitialNameTables()
{ object symbolString, classString;
object globalHashTable;
int hash;
char *p;
/* build the table that contains all symbols */
symbols = allocObject(2 * SymbolTableSize);
incr(symbols);
/* build the table (a dictionary) that contains all global names */
globalNames = allocObject(1);
globalHashTable = allocObject(3 * GlobalNameTableSize);
incr(globalNames);
basicAtPut(globalNames, 1, globalHashTable);
/* next create class Symbol, so we can call newSymbol */
/* notice newSymbol uses the global variable symbolclass */
symbolString = allocSymbol("Symbol");
symbolclass = allocObject(classSize);
setClass(symbolString, symbolclass);
basicAtPut(symbolclass, nameInClass, symbolString);
/* we recreate the hash computation used by newSymbol */
hash = 0;
for (p = "Symbol"; *p; p++)
hash += *p;
if (hash < 0) hash = - hash;
hash %= (objectSize(symbols) / 2);
basicAtPut(symbols, 2*hash + 1, symbolString);
globalNameSet(symbolString, symbolclass);
/* now the routine newSymbol should work properly */
/* now go on to make class Class so we can call makeClass */
ClassClass = allocObject(classSize);
classString = newSymbol("Class");
basicAtPut(ClassClass, nameInClass, classString);
globalNameSet(classString, ClassClass);
setClass(ClassClass, ClassClass);
setClass(symbolclass, ClassClass);
/* now create a few other important classes */
ObjectClass = makeClass("Object");
LinkClass = makeClass("Link");
setClass(nilobj, makeClass("UndefinedObject"));
DictionaryClass = makeClass("Dictionary");
ArrayClass = makeClass("Array");
setClass(symbols, DictionaryClass);
setClass(globalNames, DictionaryClass);
setClass(globalHashTable, ArrayClass);
}
/*
findClass gets a class object,
either by finding it already or making it
in addition, it makes sure it has a size, by setting
the size to zero if it is nil.
*/
static object findClass(name)
char *name;
{ object newobj;
newobj = globalSymbol(name);
if (newobj == nilobj)
newobj = makeClass(name);
if (basicAt(newobj, sizeInClass) == nilobj)
basicAtPut(newobj, sizeInClass, newInteger(0));
return(newobj);
}
/*
readDeclaration reads a declaration of a class
*/
static readDeclaration()
{ object classObj, super, vars;
int i, size, instanceTop;
object instanceVariables[15];
if (nextToken() != nameconst)
sysError("bad file format","no name in declaration");
classObj = findClass(tokenString);
size = 0;
if (nextToken() == nameconst) { /* read superclass name */
super = findClass(tokenString);
basicAtPut(classObj, superClassInClass, super);
size = intValue(basicAt(super, sizeInClass));
ignore nextToken();
}
if (token == nameconst) { /* read instance var names */
instanceTop = 0;
while (token == nameconst) {
instanceVariables[instanceTop++] = newSymbol(tokenString);
size++;
ignore nextToken();
}
vars = newArray(instanceTop);
for (i = 0; i < instanceTop; i++)
basicAtPut(vars, i+1, instanceVariables[i]);
basicAtPut(classObj, variablesInClass, vars);
}
basicAtPut(classObj, sizeInClass, newInteger(size));
}
/*
readInstance - read an instance directive
*/
static readInstance()
{ object classObj, newObj;
int size;
if (nextToken() != nameconst)
sysError("no name","following instance command");
classObj = globalSymbol(tokenString);
if (nextToken() != nameconst)
sysError("no instance name","in instance command");
/* now make a new instance of the class -
note that we can't do any initialization */
size = intValue(basicAt(classObj, sizeInClass));
newObj = allocObject(size);
setClass(newObj, classObj);
globalNameSet(newSymbol(tokenString), newObj);
}
/*
readClass reads a class method description
*/
static readClass(fd, printit)
FILE *fd;
boolean printit;
{ object classObj, methTable, theMethod, selector;
# define LINEBUFFERSIZE 512
object methDict;
char *eoftest, lineBuffer[LINEBUFFERSIZE];
/* if we haven't done it already, read symbols now */
if (trueobj == nilobj)
initCommonSymbols();
if (nextToken() != nameconst)
sysError("missing name","following Class keyword");
classObj = findClass(tokenString);
setInstanceVariables(classObj);
if (printit)
ignore fprintf(stderr,"class %s\n", charPtr(basicAt(classObj, nameInClass)));
/* find or create a methods table */
methTable = basicAt(classObj, methodsInClass);
if (methTable == nilobj) {
methTable = allocObject(1);
basicAtPut(classObj, methodsInClass, methTable);
setClass(methTable, globalSymbol("Dictionary"));
methDict = allocObject(MethodTableSize);
basicAtPut(methTable, 1, methDict);
setClass(methDict, globalSymbol("Array"));
}
/* now go read the methods */
do {
textBuffer[0] = '\0';
while((eoftest = fgets(lineBuffer, LINEBUFFERSIZE, fd)) != NULL) {
if ((lineBuffer[0] == '|') || (lineBuffer[0] == ']'))
break;
ignore strcat(textBuffer, lineBuffer);
}
if (eoftest == NULL) {
sysError("unexpected end of file","while reading method");
break;
}
/* now we have a method */
theMethod = allocObject(methodSize);
setClass(theMethod, globalSymbol("Method"));
if (parse(theMethod, textBuffer)) {
selector = basicAt(theMethod, messageInMethod);
if (printit)
ignore fprintf(stderr,"method %s\n", charPtr(selector));
nameTableInsert(methTable, selector, theMethod);
}
else {
/* get rid of unwanted method */
incr(theMethod);
decr(theMethod);
ignore fprintf(stderr,"push return to continue\n");
ignore gets(textBuffer);
}
} while (lineBuffer[0] != ']');
}
/*
readFile reads a class descriptions file
*/
readFile(fd, printit)
FILE *fd;
boolean printit;
{
while(fgets(textBuffer, TextBufferSize, fd) != NULL) {
lexinit(textBuffer);
if (token == inputend)
; /* do nothing, get next line */
else if ((token == binary) && streq(tokenString, "*"))
; /* do nothing, its a comment */
else if ((token == nameconst) && streq(tokenString, "Declare"))
readDeclaration();
else if ((token == nameconst) && streq(tokenString,"Instance"))
readInstance();
else if ((token == nameconst) && streq(tokenString,"Class"))
readClass(fd, printit);
else
ignore fprintf(stderr,"unknown line %s\n", textBuffer);
}
}