home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
me34src.zip
/
me3
/
mc
/
vcomp.c
< prev
Wrap
C/C++ Source or Header
|
1995-01-14
|
12KB
|
472 lines
/*
* vcomp.c : compile vars and the like
*/
/* Copyright 1990, 1991, 1992 Craig Durland
* Distributed under the terms of the GNU General Public License.
* Distributed "as is", without warranties of any kind, but comments,
* suggestions and bug reports are welcome.
*/
#include <stdio.h>
#include <os.h>
#include "mc.h"
#include "opcode.h"
#include "mm.h"
extern char ebuf[], token[], temp[], *typename(), *spoof();
extern unsigned int class, vtype(), mmtype();
extern int32 atoN();
extern KeyWord *global_look_for(), *global_look_up();
extern MMDatum *getconst(), *cid_to_const();
extern Var *vid_to_Var();
/* process a function pointer: foo (foo) (foo args) */
static void fcnptr(eval)
{
if (eval) /* (foo) or (foo args) */
{ genop(PUSHRV); vargs(); genop(DOOP); class = UNKNOWN; }
else class = FCNPTR;
}
/* process a var pointer: (ptr) (ptr val) */
void evalvp(arg,offset,scope,type)
{
int t = (type & ~POINTER), mt = mmtype(type);
gonumx((int32)0); genop(SHOVERV);
if (arg) { gonumx((int32)offset); genop(ARG); }
else
{
genop(SHOVERV);
gonum16((scope == LOCAL ? RVLBASE : RVGBASE),offset);
gonum8(GETRVAR,BLOB);
}
lookahead();
if (class == DELIMITER && *token == END_EXP) gonum8(GETRVAR,t); /* (ptr) */
else /* (ptr val) */
{
genop(SHOVERV); compile(); type_check(mt,0);
gonum8(SETRVAR,t);
}
class = mt;
}
/* Generate code for evaluating (returning the contents of) a local or
* global variable, prototype or constant.
* Generates code for (var) or var. Doesn't handle args, use a
* different routine.
* Input
* name : Name of variable to compile
* eval : TRUE if (name), FALSE if ... name ...
* Notes:
* Its probably not worth breaking this into two routines: one that
* looks up the name and another that compiles. The routines that
* call this (that already know the var) do so in rare cases.
*/
void genvar(name,eval) char *name;
{
int scope, offset, var_id;
unsigned int type;
KeyWord *kw;
if (-1 == (var_id = find_local_var(name))) /* not a local var or proto */
if (kw = global_look_up(name)) /* its something global */
{
switch (kw->type)
{
case KWGlobalVar:
var_id = kw->token;
break;
case KWConst:
{
MMDatum *rv;
if (!eval) /* const is legal */
{
rv = cid_to_const(kw->token);
switch (class = rv->type)
{
case STRING: gostr(RVSTR,rv->val.str); break;
case NUMBER: gonumx(rv->val.num); break;
case BOOLEAN: gonum8(RVBOOL,rv->val.num); break;
}
return;
}
/* (const) is illegal */
bitch(spoof(ebuf,"(%s [args]) not legal for a constant.%s",
name,
"\n (Can't evaluate or assign to a constant - no ()'s)."));
}
}
}
if (var_id == -1)
bitch(spoof(ebuf,"\"%s\" is not a variable or constant.",name));
/* Some type of variable */
type = vtype(var_id); offset = voffset(var_id); scope = vscope(var_id);
if (scope == PROTOTYPE) /* its a proto */
{
if (eval && (type & POINTER)) evalvp(TRUE,offset,0,type);
else
{
gonumx((int32)offset); genop(ARG);
if (type == FCNPTR) fcnptr(eval);
else
class = (type == ARRAY) ? BLOB : type;
}
return;
}
/* its a local or global variable */
if (eval && (type & POINTER)) evalvp(FALSE,offset,scope,type);
else
{
if (type == ARRAY || type == BLOB)
gonum16((scope == LOCAL ? RVLBASE : RVGBASE),offset);
else
go2num((scope == LOCAL ? GETLVAR : GETGVAR),
(type & POINTER) ? BLOB : type, offset);
if (type == FCNPTR) fcnptr(eval);
else class = type;
}
}
/* Compile a variable or prototype.
* Syntax compiled: (var [args])
* Var name has already been parsed.
* Input:
* var_id:
* -1 : Compile a local variable (name is in token[]).
* != -1 : The id of the variable to compile.
* Returns:
* FALSE : token[] not a local variable
* Notes:
* Constants not compiled.
*/
var_compile(var_id) /* handle (var [value(s)]) */
{
int arg, scope, offset;
unsigned int type;
Var *var;
MMDatum *rv;
if (var_id == -1 && (-1 == (var_id = find_local_var(token))))
return FALSE;
var = vid_to_Var(var_id);
scope = var->scope; offset = var->offset; type = var->type;
arg = (scope == PROTOTYPE);
if (type == FCNPTR) { genvar(token,TRUE); return TRUE; }
if (type == ARRAY)
{
int j,m,num_subscripts,x,z, tsize, compiled, *dim;
compiled = FALSE;
z = 0; type = var->sub_type; tsize = typesize(type);
dim = var->dim; num_subscripts = var->dims; m = num_subscripts - 1;
if (type == STRING) num_subscripts--;
for (j = 0; j < num_subscripts; j++) /* suck up subscripts */
{
lookahead();
/* check to see if next thing is a constant */
if (class == TOKEN &&
(rv = getconst(token)) && (-1 == find_local_var(token)))
{
if (rv->type == NUMBER) x = rv->val.num;
else
{
moan(spoof(ebuf,
"Constant \"%s\" is not a number - \n%s", token,
" it can't be used as a subscript."));
x = 0;
}
goto num;
}
if (class == DELIMITER || class == TOKEN)
{
if (class == DELIMITER && *token == END_EXP)
if (j == 0) /* (var) */
{
class = BLOB;
if (arg) { gonumx((int32)offset); genop(ARG); }
else gonum16((scope == LOCAL ? RVLBASE : RVGBASE),offset);
return TRUE;
}
else
{
moan(spoof(ebuf,"Need %d subscript(s).",num_subscripts));
break;
}
if (compiled) genop(SHOVERV);
compile(); type_check(NUMBER,0);
if (j < m) { genop(SHOVERV); gonumx((int32)dim[j+1]); genop(MUL); }
if (compiled) genop(ADD);
compiled = TRUE;
}
else
if (class == NUMBER)
{
x = atoN(token);
num:
get_token();
if (x < 0 || x >= dim[j])
{
moan(spoof(ebuf,"Subscript #%d (%s) out of bounds [0,%d).",
j+1, token, dim[j]));
x = 0;
}
if (j < m) x *= dim[j+1];
z += x;
}
else
{
get_token();
moan(spoof(ebuf,"\"%s\" is not an array subscript.",token));
}
}
z = z*tsize + (arg ? 0 : offset); /* offset from base address */
/* now check to see if it is assignment or eval */
lookahead();
/* TRUE => eval */
x = (class == DELIMITER && *token == END_EXP) ? TRUE : FALSE;
if (arg)
{
if (!compiled) gonumx((int32)z);
else
{
genop(SHOVERV); gonumx((int32)tsize); genop(MUL);
if (z) { genop(SHOVERV); gonumx((int32)z); genop(ADD); }
}
genop(SHOVERV);
gonumx((int32)offset); genop(ARG);
if (x) gonum8(GETRVAR,type);
else
{
genop(SHOVERV); compile(); type_check(type,0);
gonum8(SETRVAR,type);
}
}
else
{
if (!compiled)
{
if (x) go2num((scope == LOCAL ? GETLVAR : GETGVAR),type,z);
else
{
compile(); type_check(type,0);
go2num((scope == LOCAL ? SETLVAR : SETGVAR), type,z);
}
}
else
{
genop(SHOVERV); gonumx((int32)tsize); genop(MUL);
genop(SHOVERV); gonum16((scope == LOCAL ? RVLBASE : RVGBASE),z);
if (x) gonum8(GETRVAR,type);
else
{
genop(SHOVERV);
compile(); type_check(type,0);
gonum8(SETRVAR,type);
}
}
}
class = type;
return TRUE; /* done with arrays */
}
/* its a variable or constant */
lookahead();
if (class == DELIMITER && *token == END_EXP) /* (var) or (const) */
genvar(var->name,TRUE);
else /* var assignment: (var value) */
{
if (arg) /* (foo "hoho") where foo is (arg n) */
{
switch (type)
{
case LIST:
case STRING:
/* !!!??? this may not be right */
/* get the arg (an object) (I hope) */
gonumx((int32)offset); genop(ARG); genop(SHOVERV);
compile(); type_check(type,0);
gonum8(SETRVAR,type);
break;
case (POINTER | INT32): evalvp(TRUE,offset,scope,INT32); break;
case (POINTER | INT16): evalvp(TRUE,offset,scope,INT16); break;
case (POINTER | INT8): evalvp(TRUE,offset,scope,INT8); break;
case (POINTER | BOOLEAN): evalvp(TRUE,offset,scope,BOOLEAN); break;
default:
moan(spoof(ebuf,
"Can't change stack variable \"%s\" (of type %s).",
var->name, typename(var->type)));
compile(); /* try to recover */
break;
}
}
else /* (int var)(var 123) */
{
compile(); type_check(type,0);
go2num((scope == LOCAL ? SETLVAR : SETGVAR),
(type & POINTER) ? BLOB : type, offset);
}
}
return TRUE;
}
isvarok(clevel,class)
{
if (clevel == 0 || class == VAROK) return TRUE;
moan("Can't create vars here.");
return FALSE;
}
/* Compile (type var-name ...)
* For example:
* (int a) (int a b c) (array int b)
* Input:
* type: Variable type.
* local: TRUE if variable is local to a function.
* Notes:
* type already parsed (before calling this routine).
*/
void vdeclare(type,local)
{
int x, total_bytes;
x = typesize(type);
total_bytes = 0;
do
{
get_token();
if (class != TOKEN) bitch(spoof(ebuf,"%s is not a var name.",token));
create_var(token, type, x, (local ? LOCAL : GLOBAL));
total_bytes += x;
lookahead();
} while (class == TOKEN);
if (local) gonum16(LALLOC, total_bytes);
}
void pointer(local) /* (pointer type name ...) */
{
int t = -1;
KeyWord *kw;
get_token();
if (class == TOKEN && (kw = global_look_for(token, KWMutt))) t = kw->token;
switch (t)
{
case 62: vdeclare(POINTER | BOOLEAN,local); break;
case 61: vdeclare(POINTER | INT16, local); break;
case 75: vdeclare(POINTER | INT8, local); break;
case 31: vdeclare(POINTER | INT32, local); break;
case 60: vdeclare(POINTER | STRING, local); break;
default:
moan(spoof(ebuf,"%s is not a pointer type.",token));
vdeclare(POINTER | BOOLEAN,local);
}
}
static int getnum(n) int *n;
{
char *errmsg = "Array dimensions are positive numeric constants.";
int x;
MMDatum *rv;
lookahead();
if (class==DELIMITER || (class==TOKEN && (rv = getconst(token))==NULL))
return FALSE;
get_token();
if (class == TOKEN)
{
if (rv->type != NUMBER) bitch(errmsg);
x = rv->val.num;
}
else { if (class != NUMBER) bitch(errmsg); x = atoN(token); }
if (x <= 0) { moan(errmsg); x = 1; }
*n = x;
return TRUE;
}
int ntharg; /* arg & proto count for defun */
void array(scope,arg) /* (array type name subs) */
{
int t,size,x, n, dim[MAXDIM],z, tsize;
unsigned int type;
KeyWord *kw;
size = 0;
get_token();
t = -1;
if (class == TOKEN && (kw = global_look_for(token, KWMutt))) t = kw->token;
switch(t)
{
default:
moan(spoof(ebuf,"%s is not an array type.",token));
type = BOOLEAN; goto defvar;
case 62: /* (array bool name d1 ...) */
type = BOOLEAN;
defvar:
tsize = typesize(type);
do
{
z = 1; n = 0;
get_token(); strcpy(temp,token); /* get and save name */
if (class != TOKEN) bitch(spoof(ebuf,"%s is not a var name.",token));
while (TRUE)
{
if (!getnum(&x)) break;
if (n >= MAXDIM)
bitch(spoof(ebuf,"Too many dimensions (max is %d).",MAXDIM));
z *= (dim[n++] = x);
}
if (n == 0) moan("An array needs dimensions.");
z *= tsize; size += z;
if (arg) add_to_proto(temp,ntharg++,type,n,dim);
else add_array(temp,type,z,scope,n,dim);
lookahead();
} while (class == TOKEN);
if (!arg && scope == LOCAL) gonum16(LALLOC,size);
break;
case 75: type = INT8; goto defvar; /* (byte var [var ...]) */
case 61: type = INT16; goto defvar; /* (int var [var ...]) */
case 31: type = INT32; goto defvar; /* (INT var [var ...]) */
case 60: /* (array string n) */
moan("I don't support string arrays (anymore)!"); /* ??? */
#if 0
size = 0;
do
{
get_token(); strcpy(temp,token); /* get and save name */
if (class != TOKEN) bitch(spoof(ebuf,"%s is not a var name.",token));
t = getnum(&n) && getnum(&x);
if (!t || x > MAXSTRLEN)
bitch(spoof(ebuf,
"String length is a postive numeric constant <= %d.",MAXSTRLEN));
dim[0] = n; dim[1] = x+1;
z = dim[0]*dim[1]*sizeof(char);
size += z;
if (arg) add_to_proto(temp,ntharg++,STRING,2,dim);
else add_array(temp,STRING,z,scope,2,dim);
lookahead();
} while (class == TOKEN);
/* if (!arg && scope == LOCAL) gonum16(LALLOC,size);*/
#endif
break;
}
}