home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
me34src.zip
/
me3
/
mc
/
mc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-14
|
17KB
|
548 lines
/*
* mc.c : the Mutt compiler
* Craig Durland 6/87, modified in late '91 for Mutt2
*/
/* 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.
*/
static char what[] = "@(#)Mutt2 compiler 2/2/92 v2.6 2/13/94";
#define WHAT (&what[4])
#include <stdio.h>
#include <os.h>
#include "mc.h"
#include "opcode.h"
#include "mm.h"
extern char *strcpy(), *new_ext(), *spoof(), *save_string();
extern int32 atoN();
extern unsigned int codesize();
extern dumpcode();
void doc(), pilefile();
char ebuf[MAXSTRLEN+5], *muttfile = "", *include_list[10];
FILE *lstfile = NULL, *srcfile;
int errors = 0, warnings = 0, srcline = 0;
main(argc,argv) char *argv[];
{
extern char *optarg, optltr; /* in argh.c */
extern int no_warn, no_gripe; /* in supp.c */
char buf[90], *ptr = NULL, *tfname = NULL;
int j = 0, list = FALSE, x, stats = FALSE, quiet = FALSE;
while ( (x = argh(argc,argv,"I:lst:vq:")) )
switch (x)
{
case 2: ptr = optarg; break;
case 1:
switch (optltr)
{
case 'I': include_list[j++] = optarg; break;
case 'l': list = TRUE; break;
case 's': stats = TRUE; break;
case 't': tfname = optarg; break;
case 'v':
printf("%s copyright 1987-92 Craig Durland\n",WHAT);
exit(0);
case 'q': /* quiet */
x = atoi(optarg);
quiet = x & 1;
no_gripe = x & 2;
no_warn = x & 4;
break;
}
}
include_list[j] = NULL;
if (!quiet) printf("%s\n",WHAT);
if (ptr == NULL) { doc(); exit(1); }
if (list)
{
new_ext(buf,ptr,".lst");
if ((lstfile = fopen(buf,"w")) == NULL) bitch("Can't open list file.");
}
init_code_generater();
keyword_init();
var_init();
pgm_init();
if (tfname) load_ext_token_table(tfname); /* external token file */
new_ext(buf,ptr,".mut");
pilefile(buf,FALSE); finishup();
if (errors == 0) dumpcode(ptr);
spoof(ebuf,"%d Errors. %d Warnings. %u bytes of code.",
errors,warnings,codesize());
if (stats) dump_stats(stdout);
if (!quiet || stats) puts(ebuf);
if (lstfile) { fprintf(lstfile,"\n%s\n",ebuf); fclose(lstfile); }
/* hstats(); hdump(); /* */
exit(errors != 0); /* 0 if no errors, 1 if errors */
}
void doc()
{
dump_doc(
"MC2 [options] sourcefile[.MUT]",
"options: ",
" -I dir: An alternate directory for include files. One dir per -I",
" -l : Assembler output with source comments. Put into sourcefile.LST",
" -q <bits> : quiet some messages",
" Bits is a bit-or of:",
" 1 : Don't print compiler version",
" 2 : Don't print gripes",
" 4 : Don't print warnings",
" -s : Obscure compiler stats",
" -t tokenfile : tokenfile.TOK contains X-tokens",
" -v : Display the version of the compiler",
"Compiled code is put into sourcefile.MCO",
(char *)NULL);
}
extern char *catstrs();
/* open a file, search path_list if necessary */
FILE *flopen(name,path_list,mode) char *name, *path_list[], *mode;
{
char buf[300];
FILE *fptr;
int j;
if ((fptr = fopen(name,mode))) return fptr;
for (j = 0; path_list[j]; j++)
if ((fptr = fopen(catstrs(buf,path_list[j],"/",name,(char *)NULL),mode)))
return fptr;
return NULL;
}
void pilefile(fname,search) char *fname;
{
char fn[100], *ptr = muttfile;
FILE *sf = srcfile;
int sline = srcline;
srcfile = search ? flopen(fname,include_list,"r") : fopen(fname,"r");
if (srcfile == NULL) bitch(spoof(ebuf,"Can't open %s.",fname));
muttfile = strcpy(fn,fname); srcline = 0;
getsrc(); /* prime scan() */
while (compile()) ;
muttfile = ptr; srcline = sline;
fclose(srcfile); srcfile = sf;
}
/* ******************************************************************** */
/* *************************** The Compiler *************************** */
/* ******************************************************************** */
extern address getaddr(), pcaddr();
extern int ddone_label, btv;
extern KeyWord *global_look_up(), *global_look_for(), *global_check();
extern MMDatum *getconst();
char token[257], temp[257];
int breaklabel = -1, contlabel = -1;
unsigned int class = VOID;
MMDatum rv, *vtr;
#define NO_ARGS 0
#define MAYBE_ARGS 1
#define EDONE 2
static int clevel = -1, indefun = FALSE;
compile()
{
int s;
unsigned int lastclass;
clevel++;
lastclass = class; get_token();
switch(class)
{
case SEOF: clevel--; return FALSE; /* hit EOF */
case STRING: gostr(RVSTR,token); break;
case NUMBER: gonumx(atoN(token)); break;
case BOOLEAN: gonum8(RVBOOL,btv); break;
case TOKEN: genvar(token,FALSE); break;
case DELIMITER:
switch (*token)
{
case START_PGM: /* { ... } */
while (TRUE)
{
lookahead();
if (class == DELIMITER)
if (*token == END_PGM) break;
else if (*token == START_PGM) bitch("Can't nest pgms.");
class = lastclass; compile(); lastclass = class;
}
get_token(); /* suck up } */
class = lastclass;
break;
case START_IPGM: /* {{ ... }} */
if (!indefun) groan("This anon defun is dead code!");
anon_defun();
break;
case START_EXP: /* (keyword [args]) */
/* compile the keyword */
s = compile_exp(lastclass);
if (s == EDONE) goto done;
if (s == MAYBE_ARGS) /* compile the args */
{
vargs(); genop(DOOP); class = UNKNOWN;
}
lastclass = class; get_token();
if (class != DELIMITER || *token != ')')
bitch(spoof(ebuf,"Wanted ) got %s.",token));
class = lastclass;
break;
default:
bitch(spoof(ebuf,"Invalid delimiter: %s ?not enough args?",token));
}
break;
default: bitch(spoof(ebuf,"I don't reconize %s!",token));
}
done:
clevel--;
return TRUE;
}
/* Compile (keyword [args])
* Part of it anyway. Let somebody else compile the args.
* Returns:
* If need to compile args.
* Munges:
* class, token
*/
compile_exp(lastclass) unsigned int lastclass;
{
KeyWord *kw;
lookahead();
if (class == DELIMITER && *token == END_EXP) /* () */
{ class = EMPTY; return NO_ARGS; }
get_token();
switch (class)
{
case STRING: gostr(RVSTR,token); return NO_ARGS;
case NUMBER: gonumx(atoN(token)); return NO_ARGS;
case BOOLEAN: gonum8(RVBOOL,btv); return NO_ARGS;
case TOKEN: break;
default:
bitch(spoof(ebuf,
"Wanted token, string, number or boolean, got %s.",token));
}
kw = global_look_up(token);
if (kw && kw->type == KWMutt) /* Mutt keyword */
return compile_Mutt_keyword(kw->token, lastclass);
if (var_compile(-1)) return NO_ARGS;
if (kw)
{
switch (kw->type)
{
case KWXToken:
gonum16(PUSHXT,kw->token); /* !!!??? pass in name? */
return MAYBE_ARGS;
case KWGlobalVar:
var_compile(kw->token);
return NO_ARGS;
case KWConst:
genvar(token,TRUE); /* illegal, generate an error message */
return NO_ARGS;
case KWProgram:
goaddr(PUSHADDR,pgmaddr(kw->token),token);
return MAYBE_ARGS;
default: /* Unknown */
printf("????? shouldn't get here (1)!");
return NO_ARGS;
}
}
/* Unknown keyword, probably an external fcn call */
gostr(PUSHNAME,token);
return MAYBE_ARGS;
}
compile_Mutt_keyword(t, lastclass) unsigned int lastclass;
{
int l1, ldone, z;
class = lastclass;
switch (t)
{
case 64: /* (include file) */
get_token();
if (class != TOKEN && class != STRING)
bitch("include requires token or string.");
clevel--; class = include(token); clevel++;
return EDONE; /* end of this line !!! sleaze */
case 23: class = comp_if(lastclass); break; /* (if ...) */
case 5: class = comp_while(); break; /* (while ...) */
case 76: class = comp_for(); break; /* (for ...) */
case 1: class = comp_cond(); break; /* (cond ...) */
case 4: class = comp_switch(); break; /* (switch ...) */
case 2: /* (defun name pgm) */
if (clevel != 0) moan("Can't nest defuns.");
indefun = TRUE;
defun();
indefun = FALSE; class = VOID;
break;
case 8: case 6: /* (label label-name) (goto label) */
get_token();
if (class != TOKEN && class != STRING)
bitch("Label must be token or string.");
if (!indefun)
moan("Labels and gotos can only be used inside defuns.");
if ((z = get_named_label(token)) == -1)
z = gen_named_label(token);
if (t == 6) { gojmp(JMP,z); class = VOID; } /* goto */
else /* label */
{
stufflabel(z);
class = UNKNOWN; /* can get here from anywhere */
}
break;
case 7: /* (break) */
if (breaklabel == -1) moan("break not allowed here.");
else gojmp(JMP,breaklabel);
class = VOID;
break;
case 71: /* (continue) */
if (contlabel == -1) moan("continue not allowed here.");
else gojmp(JMP,contlabel);
class = VOID;
break;
case 9: genop(DONE); class = VOID; break; /* (done) */
case 16: genop(HALT); class = VOID; break; /* (halt) */
case 29: genop(RVVOID); class = VOID; break; /* (novalue) */
case 42: genop(NARGS); class = NUMBER; break; /* (nargs) */
case 43: /* (arg n) */
compile(); type_check(NUMBER,0); genop(ARG); class = UNKNOWN;
break;
case 15: /* (push-args n) */
compile(); type_check(NUMBER,0); genop(PUSHARGS);
class = PUSHEDARGS;
break;
case 17: /* (push-arg exp) */
/* Need to push if RV is a string in result.
* If RV is a function pointer, need to shove.
*/
compile();
genop( /* !!! doesn't always work for floc's */
(class == STRING || class == UNKNOWN) ? PUSHRV : SHOVERV);
class = PUSHEDARGS;
break;
case 0: /* (!= val val) */
compile(); z = class;
checkit("!=",STRING,BOOLEAN,NUMBER,0);
pushpush(); compile();
if (z != UNKNOWN) type_check(z,0); /* yukk!!! */
genop(CMP); genop(NOT); class = BOOLEAN;
break;
case 12: /* (== val val ... ) */
compile(); z = class;
checkit("==",STRING,BOOLEAN,NUMBER,0);
pushpush(); compile();
if (z != UNKNOWN) type_check(z,0); /* yukk!!! */
if (!gaze_ahead(STRING,BOOLEAN,NUMBER,0)) /* (== val val) */
genop(CMP);
else /* (== val val val [...]) */
{
l1 = genlabel();
do
{
genop(DUP); genop(CMP);
if (!gaze_ahead(STRING,BOOLEAN,NUMBER,0)) break;
gojmp(JMPFALSE,l1); compile();
if (z != UNKNOWN) type_check(z,0); /* yukk!!! */
} while (TRUE);
stufflabel(l1); genop(POP);
}
class = BOOLEAN;
break;
case 21: /* (remove-elements object n z) */
gonum16(PUSHTOKEN,REMOVE_ELS);
compile(); checkit("remove-elements", LIST,STRING,0); /* !!!ick */
/* !!!??? can't be a string constant! */
genop(SHOVERV);
compile(); type_check(NUMBER,0); genop(SHOVERV);
compile(); type_check(NUMBER,0); genop(SHOVERV);
genop(DOOP); class = VOID;
break;
case 18: /* (insert-object object n new-object ...) */
gonum16(PUSHTOKEN,INSERT_OBJ);
compile(); checkit("insert-object", LIST,STRING,0); /* !!!ick */
genop(SHOVERV);
compile(); type_check(NUMBER,0); genop(SHOVERV);
while (gaze_ahead(LIST,STRING,NUMBER,0))
{ compile(); if (class != PUSHEDARGS) genop(SHOVERV); }
genop(DOOP);
class = UNKNOWN; /* !!!Not really - its STRING or LIST */
break;
case 24: /* (extract-element object n) */
gonum16(PUSHTOKEN,EXTRACT_EL);
compile();
checkit("extract-element", LIST,STRING,0); /* !!!ick */
/* !!!??? can't be a string constant! */
genop(SHOVERV);
compile(); type_check(NUMBER,0); genop(SHOVERV);
genop(DOOP); class = UNKNOWN;
break;
case 25: /* (extract-elements object n z) */
gonum16(PUSHTOKEN,EXTRACT_ELS);
compile();
checkit("extract-elements", LIST,STRING,0); /* !!!ick */
/* !!!??? can't be a string constant! */
genop(SHOVERV);
compile(); type_check(NUMBER,0); genop(SHOVERV);
compile(); type_check(NUMBER,0); genop(SHOVERV);
genop(DOOP);
class = UNKNOWN; /* !!!Not really - its STRING or LIST */
break;
case 19: /* (length-of object) */
compile(); /* get object - can be anything */
genop(LEN_OF);
class = NUMBER;
break;
case 20: /* (convert-to type object) */
compile(); type_check(NUMBER,0); genop(SHOVERV); /* type */
compile(); /* get object - can be anything */
genop(CONVERT_TO);
class = UNKNOWN; /* !!!I can (sometimes) figure out the type */
/* !!! do some more checking here */
break;
case 28: /* (not) */
compile(); type_check(BOOLEAN,0); genop(NOT); class = BOOLEAN;
break;
case 3: opmath(ADD); break; /* (+ num num ...) */
case 67: opmath(SUB); break; /* (- num num ...) */
case 65: opmath(MUL); break; /* (* num num ...) */
case 69: opmath(DIV); break; /* (/ num num ...) */
case 63: opeq(ADD); break; /* (+= var num [num ...]) */
case 68: opeq(SUB); break; /* (-= var num [num ...]) */
case 66: opeq(MUL); break; /* (*= var num [num ...]) */
case 70: opeq(DIV); break; /* (/= var num [num ...]) */
case 11: case 14: /* (< num num), (>= num num) */
compile(); z = class;
checkit("< or >=",NUMBER,0); pushpush();
compile();
if (z != UNKNOWN) type_check(z,0); /* yukk!!! */
genop(LT);
if (t == 14) genop(NOT); /* (x >= y) == !(x < y) */
class = BOOLEAN;
break;
case 10: case 13: /* (<= num num), (> num num) */
compile(); z = class;
checkit("<= or >",NUMBER,0); pushpush();
compile();
if (z != UNKNOWN) type_check(z,0); /* yukk!!! */
genop(LTE);
if (t == 13) genop(NOT); /* (x > y) == !(x <= y) */
class = BOOLEAN;
break;
case 81: /* (or bool ...) */
z = JMPTRUE;
andor:
ldone = genlabel();
while (TRUE)
{
compile(); type_check(BOOLEAN,0);
lookahead(); if (class == DELIMITER && *token == ')') break;
gojmp(z,ldone);
}
stufflabel(ldone);
class = BOOLEAN;
break;
case 80: z = JMPFALSE; goto andor; /* (and bool bool ...) */
case 26: genop(ASKUSER); break; /* (ask-user) */
case 78: floc(); break; /* (floc fcn-name) */
case 79: loc(); break; /* (loc var-name) */
case 72: /* (pointer var) */
isvarok(clevel,class); pointer(indefun); class = lastclass;
break;
case 73: /* (array type name subs) */
isvarok(clevel,class);
array(indefun ? LOCAL : GLOBAL,FALSE); class = lastclass;
break;
case 62: /* (bool var [var ...]) */
t = BOOLEAN;
defvar:
isvarok(clevel,class); vdeclare(t,indefun); class = lastclass;
break;
case 75: t = INT8; goto defvar; /* (byte var [var ...]) */
case 61: t = INT16; goto defvar; /* (small-int var [var ...]) */
case 31: t = INT32; goto defvar; /* (int var [var ...]) */
case 60: /* (string name [name ...]) */
t = STRING; goto defobject;
case 27: /* (list name [name ...]) */
t = LIST;
defobject:
isvarok(clevel,class);
do
{
get_token();
if (class != TOKEN)
bitch(spoof(ebuf,"%s is not a var name.",token));
z = create_var(token, t, 0, (indefun ? LOCAL : GLOBAL));
if (indefun) genobj(CREATE_OBJ, LOCAL, t, voffset(z));
lookahead();
} while (class == TOKEN);
class = lastclass;
break;
case 77: /* (const name val name val ...) */
do
{
get_token();
if (class != TOKEN)
bitch(spoof(ebuf,"%s is not a const name.",token));
strcpy(temp,token);
get_token(); rv.type = class;
switch (class)
{
case NUMBER: rv.val.num = atoN(token); break;
case BOOLEAN: rv.val.num = btv; break;
case STRING: rv.val.str = save_string(token); break;
case TOKEN:
if (vtr = getconst(token)) { rv = *vtr; break; }
/* else fall though and error */
default:
moan(spoof(ebuf,"Invalid const type: %s",token));
rv.type = BOOLEAN;
}
add_const(temp,&rv);
lookahead();
} while (class == TOKEN);
class = lastclass;
break;
case 32: /* (ask ...) */
case 33: /* (concat ...) */
case 34: /* (msg ...) */
{
extern oMuttCmd *id_to_oMutt();
other_Mutt_cmd(id_to_oMutt(t));
break;
}
default: moan(spoof(ebuf,"Compiler is confused by %s.",token));
}
return NO_ARGS;
}