home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
me34src.zip
/
me3
/
mc
/
comp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-14
|
9KB
|
368 lines
/*
* comp.c : odds and ends of the compiler
* Revision History:
* 3/92 : Changed all the vararg stuff to work with stdargs.
*/
/* 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"
#ifdef __STDC__
#include <stdarg.h>
#define VA_START va_start
#else /* __STDC__ */
#include <varargs.h>
#define VA_START(a,b) va_start(a)
#endif
extern address get_pgm(), pgmaddr(), pcaddr();
extern char
ebuf[], token[],
*pgmname(), *spoof(), *typename();
extern int btv;
extern unsigned int class, vtype(), vctype(), mmtype();
extern int32 atoN();
extern MMDatum *getconst();
extern oMuttCmd *id_to_oMutt();
/* ******************************************************************** */
/* ************************** Type Checking *************************** */
/* ******************************************************************** */
static void typerr(msg,type,ap) char *msg; unsigned int type; va_list ap;
{
register unsigned int t;
spoof(ebuf,"%sexpected %s",msg,typename(type));
t = va_arg(ap,unsigned int);
while (type = t)
{
t = va_arg(ap,unsigned int);
strcat(ebuf, t ? ", " : " or ");
strcat(ebuf,typename(type));
}
strcat(ebuf,".");
moan(ebuf);
}
/* Check to see if class matches any of a list of types.
* Called: cmp_types(type,...,0);
* Returns: 0 (class is UNKNOWN), 1 (class matches), 2 (no match).
*/
static int cmp_types(type, ap) unsigned int type; va_list ap;
{
if (class == UNKNOWN) return 0;
for (; type; type = va_arg(ap,unsigned int))
{
if (class == type ||
(mmtype(type) == NUMBER && mmtype(class) == NUMBER) ||
((class & POINTER) && (type & POINTER)))
return 1;
}
return 2;
}
/* Zero terminated list of ONE type (eg type_check(NUMBER,0)).
* More than one type will mess things up.
* Written in this strange way so I can call cmp_types().
*/
/*VARARGS1*/
#ifdef __STDC__
void type_check(unsigned int type, ...)
#else
void type_check(type, va_alist) unsigned int type; va_dcl
#endif
{
int n;
va_list ap;
VA_START(ap,type);
n = cmp_types(type, ap);
switch(n)
{
case 0: gonum8(TYPECHECK,mmtype(type)); break;
case 2: VA_START(ap,type); typerr("Type mismatch: ",type,ap); break;
}
va_end(ap);
class = type;
}
/*VARARGS2*/
#ifdef __STDC__
void checkit(char *msg, unsigned int type, ...)
#else
void checkit(msg, type, va_alist)
char *msg; unsigned int type; va_dcl /* zero terminated list of types */
#endif
{
char buf[90];
va_list ap;
VA_START(ap,type);
if (cmp_types(type, ap) == 2)
{
VA_START(ap,type);
typerr(spoof(buf,"%s: Invalid type: ",msg), type,ap);
}
va_end(ap);
}
/* returns TRUE if conditions met */
/*VARARGS1*/
#ifdef __STDC__
gaze_ahead(unsigned int tipe, ...)
#else
gaze_ahead(tipe, va_alist)
unsigned int tipe; va_dcl /* zero terminated list of types */
#endif
{
int t;
unsigned int type;
MMDatum *rv;
va_list ap;
lookahead();
if (class == DELIMITER)
if (*token == START_EXP || *token == START_PGM) return TRUE;
else return FALSE;
VA_START(ap,tipe);
if (class == TOKEN) /* check for var or const */
{
for (type = tipe; type; type = va_arg(ap,unsigned int))
if (type == TOKEN) goto ok; /* class == type */
if ((t = getvar(token)) != -1) /* local or global var or prototype */
class = vctype(t);
else
if (rv = getconst(token)) class = rv->type; /* constant */
}
VA_START(ap, tipe);
if (cmp_types(tipe,ap) == 2)
{ VA_START(ap, tipe); typerr("Invalid type: ",tipe,ap); }
ok:
va_end(ap);
return TRUE;
}
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* Generate the minimum code needed to push an arg of type class */
void pushpush()
{
switch (class)
{
case EMPTY:
case PUSHEDARGS: return; /* nothing to push */
case STRING:
/* case FCNPTR: /* ??? am I sure about fcnptr?? */
case UNKNOWN: genop(PUSHRV); break;
default: genop(SHOVERV);
}
}
void vargs() /* compile args and push them */
{
while (TRUE)
{
lookahead();
if (class == DELIMITER)
if (*token == START_EXP || *token == START_PGM || *token == START_IPGM)
{ compile(); pushpush(); continue; }
else
if (*token == END_EXP) break;
else bitch("vargs is confused");
switch (class)
{
case STRING: gostr(RVSTR,token); genop(SHOVERV); break;
case NUMBER: gonumx(atoN(token)); genop(SHOVERV); break;
case BOOLEAN: gonum8(RVBOOL,btv); genop(SHOVERV); break;
case TOKEN: genvar(token,FALSE); genop(SHOVERV); break;
default: bitch(spoof(ebuf,"Invalid parameter: %s",token));
}
get_token(); /* suck up token we just compiled */
}
}
void opmath(opcode) /* stuff like (+ 1 2 3) */
{
compile(); type_check(NUMBER,0);
do { genop(SHOVERV); compile(); type_check(NUMBER,0); genop(opcode); }
while (gaze_ahead(NUMBER,0));
class = NUMBER;
}
void opeq(opcode) /* stuff like (+= var 1 2 3) */
{
int t, scope, offset = 0;
unsigned int type = 0;
get_token();
if (class != TOKEN)
{
spoof(ebuf,"%s is not a var name.",token);
if (class == DELIMITER) bitch(ebuf); else moan(ebuf);
}
else
if ((t = getvar(token)) == -1)
moan(spoof(ebuf,"Var %s not created yet.",token));
else
{
if (vctype(t) != NUMBER)
moan(spoof(ebuf,"Var %s needs to be numeric.",token));
type = vtype(t); scope = vscope(t); offset = voffset(t);
}
go2num((scope == LOCAL ? GETLVAR : GETGVAR),type,offset);
do { genop(SHOVERV); compile(); type_check(NUMBER,0); genop(opcode); }
while (gaze_ahead(NUMBER,0));
go2num((scope == LOCAL ? SETLVAR : SETGVAR),type,offset);
class = NUMBER;
}
/* floc: function location (address).
* Syntax:
* (floc <STRING | TOKEN | string-var> [args])
*/
void floc()
{
extern KeyWord *global_look_up();
oMuttCmd *ptr;
lookahead();
if (class == TOKEN) /* (floc foo) */
{
KeyWord *kw;
if (kw = global_look_up(token))
{
switch (kw->type)
{
case KWoMutt:
ptr = id_to_oMutt(kw->token);
genfp(OPTOKEN, ptr->token, token);
break;
case KWXToken: genfp(OPXTOKEN,kw->token,token); break;
case KWProgram: genfa(pgmaddr(kw->token),token); break;
}
}
else genfa((address)NIL, token); /* resolve it later */
get_token();
}
else /* (floc "foo"), (floc (...)) */
{ compile(); type_check(STRING,0); genfp(OPNAME,0,""); }
/* !!!??? how come (string foo) (floc (foo)()) works but (floc foo()) don't?
*/
lookahead();
if (class == DELIMITER && *token == END_EXP) class = FCNPTR;
else /* (floc name args) => gen fcn call */
{
genop(PUSHRV); /* push will set op stack for fcn call */
vargs(); /* compile fcn args */
genop(DOOP); /* call the fcn */
class = UNKNOWN;
}
}
/* loc: variable location (address)
* Syntax: (loc TOKEN) where token is the name of a variable.
*/
void loc()
{
int t, scope, offset;
lookahead();
if (class == TOKEN)
{
get_token();
if ((t = getvar(token)) != -1) /* (loc var-name) */
{
if (vtype(t) == STRING || vtype(t) == LIST)
moan(spoof(ebuf,"I need to think about (loc STRING) & (loc LIST): %s",token));
scope = vscope(t); offset = voffset(t);
gonum16((scope == LOCAL ? RVLBASE : RVGBASE),offset);
class = POINTER | vtype(t);
}
else /* a token but not a variable */
{
moan(spoof(ebuf,
"(loc): Expected a variable name, not a \"%s\".", token));
class = POINTER | BOOLEAN;
}
}
else /* not even a token */
{
moan(spoof(ebuf,
"(loc): Expected a variable name, not a \"%s\".", token));
compile(); class = POINTER | BOOLEAN;
}
}
other_Mutt_cmd(ptr) oMuttCmd *ptr;
{
if (ptr)
{
gonum16(PUSHTOKEN,ptr->token);
vargs(); genop(DOOP);
class = ptr->class;
return TRUE;
}
return FALSE;
}
/* Generate code to create the global objects and call all the MAIN
* functions.
* Notes:
* If no MAINs and no global objects, this is a no-op but I need an
* entry point (by definition) so just put a (done) at the entry
* point.
* The init code is put after all other code.
*/
void finishup()
{
extern address entrypt; /* in code.c */
int n;
link(); /* !!! should really check for errors better */
entrypt = pcaddr(); /* Address of init code */
for (n = 0; (n = get_global_object(n)) != -1; n++)
genobj(CREATE_OBJ, GLOBAL, vtype(n), voffset(n));
sort_pgms(); /* So I call the MAIN's in order */
for (n = 0; (n = get_main(n)) != -1; n++)
{ goaddr(PUSHADDR, pgmaddr(n), pgmname(n)); genop(DOOP); }
genop(DONE); /* terminate init code */
}