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 >
C/C++ Source or Header  |  1986-11-20  |  9KB  |  333 lines

  1. /*
  2.     Little Smalltalk, version 2
  3.     Written by Tim Budd, Oregon State University, July 1987
  4.  
  5.     routines used in the making of the initial object image
  6. */
  7.  
  8. # include <stdio.h>
  9. # include "env.h"
  10. # include "memory.h"
  11. # include "names.h"
  12. # include "lex.h"
  13. # ifdef STRING
  14. # include <string.h>
  15. # endif
  16. # ifdef STRINGS
  17. # include <strings.h>
  18. # endif
  19.  
  20. # define SymbolTableSize 71
  21. # define GlobalNameTableSize 53
  22. # define MethodTableSize 39
  23.  
  24. # define globalNameSet(sym, value) nameTableInsert(globalNames, sym, value)
  25. /*
  26.     the following classes are used repeately, so we put them in globals.
  27. */
  28. static object ObjectClass;
  29. static object ClassClass;
  30. static object LinkClass;
  31. static object DictionaryClass;
  32. static object ArrayClass;
  33.  
  34. /*
  35.     we read the input a line at a time, putting lines into the following
  36.     buffer.  In addition, all methods must also fit into this buffer.
  37. */
  38. # define TextBufferSize 1024
  39. static char textBuffer[TextBufferSize];
  40.  
  41. /*
  42.     nameTableInsert is used to insert a symbol into a name table.
  43.     see names.c for futher information on name tables
  44. */
  45. nameTableInsert(dict, symbol, value)
  46. object dict, symbol, value;
  47. {    object table, link, newLink, nextLink, tablentry;
  48.     int hash;
  49.  
  50. #ifdef AMIGA
  51.     int temptablesize;
  52. #endif
  53.  
  54.     /* first get the hash table */
  55.     table = basicAt(dict, 1);
  56.  
  57. #ifdef AMIGA
  58.     temptablesize = objectSize(table);
  59.     if (temptablesize < 3)
  60. #else
  61.     if (objectSize(table) < 3)
  62. #endif
  63.         sysError("attempt to insert into","too small name table");
  64.     else {
  65.         hash = 3 * ( symbol % (objectSize(table) / 3));
  66.         tablentry = basicAt(table, hash+1);
  67.         if ((tablentry == nilobj) || (tablentry == symbol)) {
  68.             basicAtPut(table, hash+1, symbol);
  69.             basicAtPut(table, hash+2, value);
  70.             }
  71.         else {
  72.             newLink = allocObject(3);
  73.             incr(newLink);
  74.             setClass(newLink, globalSymbol("Link"));
  75.             basicAtPut(newLink, 1, symbol);
  76.             basicAtPut(newLink, 2, value);
  77.             link = basicAt(table, hash+3);
  78.             if (link == nilobj)
  79.                 basicAtPut(table, hash+3, newLink);
  80.             else
  81.                 while(1)
  82.                     if (basicAt(link,1) == symbol) {
  83.                         basicAtPut(link, 2, value);
  84.                         break;
  85.                         }
  86.                     else if ((nextLink = basicAt(link, 3)) == nilobj) {
  87.                         basicAtPut(link, 3, newLink);
  88.                         break;
  89.                         }
  90.                     else
  91.                         link = nextLink;
  92.             decr(newLink);
  93.             }
  94.     }
  95. }
  96.  
  97. /*
  98.     there is sort of a chicken and egg problem about building the
  99.     first classes.
  100.     in order to do it, you need symbols,
  101.     but in order to make symbols, you need the class Symbol.
  102.     the routines makeClass and buildInitialNameTable attempt to get
  103.     carefully get around this initialization problem
  104. */
  105.  
  106. static object makeClass(name)
  107. char *name;
  108. {    object theClass, theSymbol;
  109.  
  110.     /* this can only be called once newSymbol works properly */
  111.  
  112.     theClass = allocObject(classSize);
  113.     theSymbol = newSymbol(name);
  114.     basicAtPut(theClass, nameInClass, theSymbol);
  115.     globalNameSet(theSymbol, theClass);
  116.     setClass(theClass, ClassClass);
  117.  
  118.     return(theClass);
  119. }
  120.  
  121. buildInitialNameTables()
  122. {    object symbolString, classString;
  123.     object globalHashTable;
  124.     int hash;
  125.     char *p;
  126.  
  127.     /* build the table that contains all symbols */
  128.     symbols = allocObject(2 * SymbolTableSize);
  129.     incr(symbols);
  130.  
  131.     /* build the table (a dictionary) that contains all global names */
  132.     globalNames = allocObject(1);
  133.     globalHashTable = allocObject(3 * GlobalNameTableSize);
  134.     incr(globalNames);
  135.     basicAtPut(globalNames, 1, globalHashTable);
  136.  
  137.     /* next create class Symbol, so we can call newSymbol */
  138.     /* notice newSymbol uses the global variable symbolclass */
  139.     symbolString = allocSymbol("Symbol");
  140.     symbolclass =  allocObject(classSize);
  141.     setClass(symbolString, symbolclass);
  142.     basicAtPut(symbolclass, nameInClass, symbolString);
  143.     /* we recreate the hash computation used by newSymbol */
  144.     hash = 0;
  145.     for (p = "Symbol"; *p; p++)
  146.         hash += *p;
  147.     if (hash < 0) hash = - hash;
  148.     hash %= (objectSize(symbols) / 2);
  149.     basicAtPut(symbols, 2*hash + 1, symbolString);
  150.     globalNameSet(symbolString, symbolclass);
  151.     /* now the routine newSymbol should work properly */
  152.  
  153.     /* now go on to make class Class so we can call makeClass */
  154.     ClassClass = allocObject(classSize);
  155.     classString = newSymbol("Class");
  156.     basicAtPut(ClassClass, nameInClass, classString);
  157.     globalNameSet(classString, ClassClass);
  158.     setClass(ClassClass, ClassClass);
  159.     setClass(symbolclass, ClassClass);
  160.  
  161.     /* now create a few other important classes */
  162.     ObjectClass = makeClass("Object");
  163.     LinkClass = makeClass("Link");
  164.     setClass(nilobj, makeClass("UndefinedObject"));
  165.     DictionaryClass = makeClass("Dictionary");
  166.     ArrayClass = makeClass("Array");
  167.     setClass(symbols, DictionaryClass);
  168.     setClass(globalNames, DictionaryClass);
  169.     setClass(globalHashTable, ArrayClass);
  170.  
  171. }
  172.  
  173. /*
  174.     findClass gets a class object,
  175.     either by finding it already or making it
  176.     in addition, it makes sure it has a size, by setting
  177.     the size to zero if it is nil.
  178. */
  179. static object findClass(name)
  180. char *name;
  181. {    object newobj;
  182.  
  183.     newobj = globalSymbol(name);
  184.     if (newobj == nilobj)
  185.         newobj = makeClass(name);
  186.     if (basicAt(newobj, sizeInClass) == nilobj)
  187.         basicAtPut(newobj, sizeInClass, newInteger(0));
  188.     return(newobj);
  189. }
  190.  
  191. /*
  192.     readDeclaration reads a declaration of a class
  193. */
  194. static readDeclaration()
  195. {    object classObj, super, vars;
  196.     int i, size, instanceTop;
  197.     object instanceVariables[15];
  198.  
  199.     if (nextToken() != nameconst)
  200.         sysError("bad file format","no name in declaration");
  201.     classObj = findClass(tokenString);
  202.     size = 0;
  203.     if (nextToken() == nameconst) { /* read superclass name */
  204.         super = findClass(tokenString);
  205.         basicAtPut(classObj, superClassInClass, super);
  206.         size = intValue(basicAt(super, sizeInClass));
  207.         ignore nextToken();
  208.         }
  209.     if (token == nameconst) {               /* read instance var names */
  210.         instanceTop = 0;
  211.         while (token == nameconst) {
  212.             instanceVariables[instanceTop++] = newSymbol(tokenString);
  213.             size++;
  214.             ignore nextToken();
  215.             }
  216.         vars = newArray(instanceTop);
  217.         for (i = 0; i < instanceTop; i++)
  218.             basicAtPut(vars, i+1, instanceVariables[i]);
  219.         basicAtPut(classObj, variablesInClass, vars);
  220.         }
  221.     basicAtPut(classObj, sizeInClass, newInteger(size));
  222. }
  223.  
  224. /*
  225.     readInstance - read an instance directive
  226. */
  227. static readInstance()
  228. {    object classObj, newObj;
  229.     int size;
  230.  
  231.     if (nextToken() != nameconst)
  232.         sysError("no name","following instance command");
  233.     classObj = globalSymbol(tokenString);
  234.     if (nextToken() != nameconst)
  235.         sysError("no instance name","in instance command");
  236.  
  237.     /* now make a new instance of the class -
  238.         note that we can't do any initialization */
  239.     size = intValue(basicAt(classObj, sizeInClass));
  240.     newObj = allocObject(size);
  241.     setClass(newObj, classObj);
  242.     globalNameSet(newSymbol(tokenString), newObj);
  243. }
  244.  
  245. /*
  246.     readClass reads a class method description
  247. */
  248. static readClass(fd, printit)
  249. FILE *fd;
  250. boolean printit;
  251. {    object classObj, methTable, theMethod, selector;
  252. # define LINEBUFFERSIZE 512
  253.     object methDict;
  254.     char *eoftest, lineBuffer[LINEBUFFERSIZE];
  255.  
  256.     /* if we haven't done it already, read symbols now */
  257.     if (trueobj == nilobj)
  258.         initCommonSymbols();
  259.  
  260.     if (nextToken() != nameconst)
  261.         sysError("missing name","following Class keyword");
  262.     classObj = findClass(tokenString);
  263.     setInstanceVariables(classObj);
  264.     if (printit)
  265. ignore fprintf(stderr,"class %s\n", charPtr(basicAt(classObj, nameInClass)));
  266.  
  267.     /* find or create a methods table */
  268.     methTable = basicAt(classObj, methodsInClass);
  269.     if (methTable == nilobj) {
  270.         methTable = allocObject(1);
  271.         basicAtPut(classObj, methodsInClass, methTable);
  272.         setClass(methTable, globalSymbol("Dictionary"));
  273.         methDict = allocObject(MethodTableSize);
  274.         basicAtPut(methTable, 1, methDict);
  275.         setClass(methDict, globalSymbol("Array"));
  276.         }
  277.  
  278.     /* now go read the methods */
  279.     do {
  280.         textBuffer[0] = '\0';
  281.         while((eoftest = fgets(lineBuffer, LINEBUFFERSIZE, fd)) != NULL) {
  282.             if ((lineBuffer[0] == '|') || (lineBuffer[0] == ']'))
  283.                 break;
  284.             ignore strcat(textBuffer, lineBuffer);
  285.             }
  286.         if (eoftest == NULL) {
  287.             sysError("unexpected end of file","while reading method");
  288.             break;
  289.             }
  290.         /* now we have a method */
  291.         theMethod = allocObject(methodSize);
  292.         setClass(theMethod, globalSymbol("Method"));
  293.         if (parse(theMethod, textBuffer)) {
  294.             selector = basicAt(theMethod, messageInMethod);
  295.             if (printit)
  296. ignore fprintf(stderr,"method %s\n", charPtr(selector));
  297.             nameTableInsert(methTable, selector, theMethod);
  298.             }
  299.         else {
  300.             /* get rid of unwanted method */
  301.             incr(theMethod);
  302.             decr(theMethod);
  303. ignore fprintf(stderr,"push return to continue\n");
  304. ignore gets(textBuffer);
  305.             }
  306.  
  307.     } while (lineBuffer[0] != ']');
  308. }
  309.  
  310. /*
  311.     readFile reads a class descriptions file
  312. */
  313. readFile(fd, printit)
  314. FILE *fd;
  315. boolean printit;
  316. {
  317.     while(fgets(textBuffer, TextBufferSize, fd) != NULL) {
  318.         lexinit(textBuffer);
  319.         if (token == inputend)
  320.             ; /* do nothing, get next line */
  321.         else if ((token == binary) && streq(tokenString, "*"))
  322.             ; /* do nothing, its a comment */
  323.         else if ((token == nameconst) && streq(tokenString, "Declare"))
  324.             readDeclaration();
  325.         else if ((token == nameconst) && streq(tokenString,"Instance"))
  326.             readInstance();
  327.         else if ((token == nameconst) && streq(tokenString,"Class"))
  328.             readClass(fd, printit);
  329.         else
  330.             ignore fprintf(stderr,"unknown line %s\n", textBuffer);
  331.         }
  332. }
  333.