home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 5
/
FreshFish_July-August1994.bin
/
bbs
/
dev
/
alst-3.04.lha
/
ALSt-3.04
/
src
/
parser.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-14
|
21KB
|
818 lines
/*
Little Smalltalk, version 2
Written by Tim Budd, Oregon State University, July 1987
Method parser - parses the textual description of a method,
generating bytecodes and literals.
This parser is based around a simple minded recursive descent
parser.
It is used both by the module that builds the initial virtual image,
and by a primitive when invoked from a running Smalltalk system.
The latter case could, if the bytecode interpreter were fast enough,
be replaced by a parser written in Smalltalk. This would be preferable,
but not if it slowed down the system too terribly.
To use the parser the routine setInstanceVariables must first be
called with a class object. This places the appropriate instance
variables into the memory buffers, so that references to them
can be correctly encoded.
As this is recursive descent, you should read it SDRAWKCAB !
(from bottom to top)
*/
# include <stdio.h>
# include <ctype.h>
# include "env.h"
# include "memory.h"
# include "names.h"
# include "interp.h"
# include "lex.h"
# ifdef STRING
# include <string.h>
# endif
# ifdef STRINGS
# include <strings.h>
# endif
/* all of the following limits could be increased (up to
256) without any trouble. They are kept low
to keep memory utilization down */
# define codeLimit 256 /* maximum number of bytecodes permitted */
# define literalLimit 128 /* maximum number of literals permitted */
# define temporaryLimit 32 /* maximum number of temporaries permitted */
# define argumentLimit 32 /* maximum number of arguments permitted */
# define instanceLimit 32 /* maximum number of instance vars permitted */
# define methodLimit 64 /* maximum number of methods permitted */
boolean parseok; /* parse still ok? */
extern char peek();
static int codeTop; /* top position filled in code array */
static byte codeArray[codeLimit]; /* bytecode array */
static int literalTop; /* ... etc. */
static object literalArray[literalLimit];
static int temporaryTop;
static char *temporaryName[temporaryLimit];
static int argumentTop;
static char *argumentName[argumentLimit];
static int instanceTop;
static char *instanceName[instanceLimit];
static int maxTemporary; /* highest temporary see so far */
static char selector[80]; /* message selector */
enum blockstatus {NotInBlock, InBlock, OptimizedBlock} blockstat;
setInstanceVariables(aClass)
object aClass;
{ int i, limit;
object vars;
if (aClass == nilobj)
instanceTop = 0;
else {
setInstanceVariables(basicAt(aClass, superClassInClass));
vars = basicAt(aClass, variablesInClass);
if (vars != nilobj) {
limit = sizeField(vars);
for (i = 1; i <= limit; i++)
instanceName[++instanceTop] = charPtr(basicAt(vars, i));
}
}
}
static genCode(value)
int value;
{
if (codeTop >= codeLimit)
compilError(selector,"too many bytecode instructions in method","");
else
codeArray[codeTop++] = value;
}
static genInstruction(high, low)
int high, low;
{
if (low >= 16) {
genInstruction(Extended, high);
genCode(low);
}
else
genCode(high * 16 + low);
}
static int genLiteral(aLiteral)
object aLiteral;
{
if (literalTop >= literalLimit)
compilError(selector,"too many literals in method","");
else {
literalArray[++literalTop] = aLiteral;
incr(aLiteral);
}
return(literalTop - 1);
}
static genInteger(val) /* generate an integer push */
int val;
{
if (val == -1)
genInstruction(PushConstant, minusOne);
else if ((val >= 0) && (val <= 2))
genInstruction(PushConstant, val);
else
genInstruction(PushLiteral,
genLiteral(newInteger(val)));
}
static char *glbsyms[] = {"currentInterpreter", "nil", "true", "false",
0 };
static boolean nameTerm(name)
char *name;
{ int i;
boolean done = false;
boolean isSuper = false;
/* it might be self or super */
if (streq(name, "self") || streq(name, "super")) {
genInstruction(PushArgument, 0);
done = true;
if (streq(name,"super")) isSuper = true;
}
/* or it might be a temporary (reverse this to get most recent first)*/
if (! done)
for (i = temporaryTop; (! done) && ( i >= 1 ) ; i--)
if (streq(name, temporaryName[i])) {
genInstruction(PushTemporary, i-1);
done = true;
}
/* or it might be an argument */
if (! done)
for (i = 1; (! done) && (i <= argumentTop ) ; i++)
if (streq(name, argumentName[i])) {
genInstruction(PushArgument, i);
done = true;
}
/* or it might be an instance variable */
if (! done)
for (i = 1; (! done) && (i <= instanceTop); i++) {
if (streq(name, instanceName[i])) {
genInstruction(PushInstance, i-1);
done = true;
}
}
/* or it might be a global constant */
if (! done)
for (i = 0; (! done) && glbsyms[i]; i++)
if (streq(name, glbsyms[i])) {
genInstruction(PushConstant, i+4);
done = true;
}
/* not anything else, it must be a global */
/* must look it up at run time */
if (! done) {
genInstruction(PushLiteral, genLiteral(newSymbol(name)));
genMessage(false, 0, newSymbol("value"));
}
return(isSuper);
}
static int parseArray()
{ int i, size, base;
object newLit, obj;
base = literalTop;
ignore nextToken();
while (parseok && (token != closing)) {
switch(token) {
case arraybegin:
ignore parseArray();
break;
case intconst:
ignore genLiteral(newInteger(tokenInteger));
ignore nextToken();
break;
case floatconst:
ignore genLiteral(newFloat(tokenFloat));
ignore nextToken();
break;
case nameconst: case namecolon: case symconst:
ignore genLiteral(newSymbol(tokenString));
ignore nextToken();
break;
case binary:
if (streq(tokenString, "(")) {
ignore parseArray();
break;
}
if (streq(tokenString, "-") && isdigit(peek())) {
ignore nextToken();
if (token == intconst)
ignore genLiteral(newInteger(- tokenInteger));
else if (token == floatconst) {
ignore genLiteral(newFloat(-tokenFloat));
}
else
compilError(selector,"negation not followed",
"by number");
ignore nextToken();
break;
}
ignore genLiteral(newSymbol(tokenString));
ignore nextToken();
break;
case charconst:
ignore genLiteral(newChar( tokenInteger));
ignore nextToken();
break;
case strconst:
ignore genLiteral(newStString(tokenString));
ignore nextToken();
break;
default:
compilError(selector,"illegal text in literal array",
tokenString);
ignore nextToken();
break;
}
}
if (parseok)
if (! streq(tokenString, ")"))
compilError(selector,"array not terminated by right parenthesis",
tokenString);
else
ignore nextToken();
size = literalTop - base;
newLit = newArray(size);
for (i = size; i >= 1; i--) {
obj = literalArray[literalTop];
basicAtPut(newLit, i, obj);
decr(obj);
literalArray[literalTop] = nilobj;
literalTop = literalTop - 1;
}
return(genLiteral(newLit));
}
static boolean term()
{ boolean superTerm = false; /* true if term is pseudo var super */
if (token == nameconst) {
superTerm = nameTerm(tokenString);
ignore nextToken();
}
else if (token == intconst) {
genInteger(tokenInteger);
ignore nextToken();
}
else if (token == floatconst) {
genInstruction(PushLiteral, genLiteral(newFloat(tokenFloat)));
ignore nextToken();
}
else if ((token == binary) && streq(tokenString, "-")) {
ignore nextToken();
if (token == intconst)
genInteger(- tokenInteger);
else if (token == floatconst) {
genInstruction(PushLiteral,
genLiteral(newFloat(-tokenFloat)));
}
else
compilError(selector,"negation not followed",
"by number");
ignore nextToken();
}
else if (token == charconst) {
genInstruction(PushLiteral,
genLiteral(newChar(tokenInteger)));
ignore nextToken();
}
else if (token == symconst) {
genInstruction(PushLiteral,
genLiteral(newSymbol(tokenString)));
ignore nextToken();
}
else if (token == strconst) {
genInstruction(PushLiteral,
genLiteral(newStString(tokenString)));
ignore nextToken();
}
else if (token == arraybegin) {
genInstruction(PushLiteral, parseArray());
}
else if ((token == binary) && streq(tokenString, "(")) {
ignore nextToken();
express