home *** CD-ROM | disk | FTP | other *** search
- /* bsint.c -- main part of interpretor.
- */
-
- #include "bsdefs.h"
-
- int (*_null[])() = { 0,0 };
-
- struct line llist[NUMLINES] = {
- 0, _null, "",
- MAXLN, _null, ""
- };
-
- struct line *lastline = &llist[1];
- struct line *Thisline = &llist[0];
- int Thisp = 0;
-
- struct dictnode vlist[VLSIZ];
-
-
- /* bslash() -- have seen '\', use input() to say what is actually wanted.
- */
- char bslash()
- {
- char text[8];
- register char *s,c;
- int v;
-
- c=input();
- if(c == 'n') c='\n';
- else if(c == 't') c='\t';
- else if(c == 'b') c='\b';
- else if(c == 'r') c='\r';
- else if(c == 'f') c='\f';
- else if(c>='0' && c<='7') { /* octal digit string */
- s = &text[0];
- *s++ = c;
- c=input();
- while(c>='0' && c<='7') {
- *s++ = c;
- c=input();
- }
- *s++ = '\0';
- sscanf(text,"%o",&v);
- c = (char) v;
- }
- else if(c=='\n') rdlin(bsin);
- return(c);
- }
-
-
- /* scon_in() -- read in a string constant using input.
- * Format of an scon is either a quoted string, or a sequence
- * of characters ended with a seperator (' ', '\t' or '\n' or ',').
- *
- * In either mode, you can get funny characters into the string by
- * "quoting" them with a '\'.
- *
- * scon_in() uses myalloc() to create space to store the string in.
- */
- char *scon_in()
- {
- register char c,*s;
- static char text [80];
-
- s = &text[0];
-
- /* beginning state, skip seperators until something interesting comes along */
-
- l1: c=input();
- if(c == '"') goto l2;
- else if(c=='\n' || c=='\0') {
- rdlin(bsin);
- goto l1;
- }
- else if(c==' ' || c=='\t' || c==',') goto l1;
- else goto l3;
-
- /* have skipped unwanted material, seen a '"', read in a quoted string */
-
- l2: c=input();
- if(c == '\n') {
- fprintf(stderr,"scon_in: unterminated string\n");
- exit(1);
- }
- else if(c == '\\') { *s++ = bslash(bsin); goto l2; }
- else if(c == '"')
- if((c=input()) == '"') {
- *s++ = '"';
- goto l2;
- }
- else goto done;
- else { *s++ = c; goto l2; }
-
- /* skipped unwanted, seen something interesting, not '"', gather until sep */
-
- l3: *s++ = c;
- c=input();
- if(c == '\\') { c = bslash(bsin); goto l3; }
- else if(c==' ' || c=='\t' || c==',' || c=='\n') goto done;
- else goto l3;
-
- /* final state (if machine finished ok.) */
-
- done: unput(c);
- *s++ = '\0';
- s=myalloc(strlen(text)+1);
- strcpy(s,text);
- return(s);
- }
-
- /* int_in() -- tokenizer routine for inputting a number.
- * int_in() returns a pointer to a static data area. This area gets
- * overwritten with each call to int_in so use the data before calling
- * int_in() again.
- */
- char * int_in()
- {
- register char c,*s;
- static char text[20];
-
- s = &text[0];
-
- /* beginning state, skip junk until either '-' or ['0'-'9'] comes along */
-
- l1: c=input();
- if(c>='0' && c<='9') goto l3;
- else if(c == '-') goto l2;
- else {
- if(c=='\n' || c=='\0') rdlin(bsin);
- goto l1;
- }
-
- /* skipped junk, seen '-', gather it and make sure next char is a digit */
-
- l2: *s++ = c;
- c=input();
- if(c==' ' || c=='\t') goto l2; /* allow white between sign and digit */
- else if(c>='0' && c<='9') goto l3;
- else { /* seen something not allowed. */
- s = &text[0];
- printf("\n\007??");
- goto l1; /* restart machine */
- }
-
- /* skipped junk, seen a digit, gather until a non-digit appears */
-
- l3: *s++ = c;
- c=input();
- if(c>='0' && c<='9') goto l3;
- else {
- /* have reached successful conclusion to machine. */
- unput(c);
- *s++ = '\0';
- return(text);
- }
- }
-
- /* real_in() -- read in a floating point number using input().
- *
- * real_in() returns a pointer to a static data area. This data area
- * gets overwritten with each call to real_in(), so use it quickly.
- */
- char *real_in()
- {
- register char *s,c;
- static char bf[30];
-
- s = &bf[0];
-
- /* starting state. loops back until something interesting seen */
-
- state1: c=input();
- if(c == '-') goto state3;
- else if(c>='0' && c<='9') goto state2;
- else if(c == '.') goto state4;
- else {
- if(c=='\n' || c=='\0') rdlin(bsin);
- goto state1;
- }
-
- /* seen a digit. gather all digits following. */
-
- state2: *s++ = c;
- c=input();
- if(c>='0' && c<='9') goto state2;
- else if(c == '.') goto state4;
- else goto state9; /* done */
-
- /* seen a sign character before start of number. loop back for whitespace. */
-
- state3: *s++ = c;
- state3_a: c=input();
- if(c==' ' || c=='\t') goto state3_a;
- else if(c>='0' && c<='9') goto state2;
- else if(c == '.') goto state4;
- else goto state10; /* error, had a sign so we have to have digs. */
-
- /* seen digit(s) and a decimal point. looking for more digs or ('e'|'E') */
-
- state4: *s++ = c;
- c=input();
- if(c>='0' && c<='9') goto state5;
- else if(c=='e' || c=='E') goto state6;
- else goto state9; /* done */
-
- /* seen (digs '.' dig). look for more digs or ('e'|'E'). */
-
- state5: *s++ = c;
- c=input();
- if(c=='e' || c=='E') goto state6;
- else if(c>='0' && c<='9') goto state5;
- else goto state9;
-
- /* seen (digs '.' digs (e|E)). looking for sign or digs, else error. */
-
- state6: *s++ = c;
- c=input();
- if(c=='+' || c=='-') goto state7;
- else if(c>='0' && c<='9') goto state8;
- else goto state10; /* error */
-
- /* seen (digs '.' digs (e|E) sign). looking for digs, else error. */
-
- state7: *s++ = c;
- c=input();
- if(c>='0' && c<='9') goto state8;
- else goto state10; /* error */
-
- /* seen (digs '.' digs (e|E) [sign] dig). looking for digs. */
-
- state8: *s++ = c;
- c=input();
- if(c>='0' && c<='9') goto state8;
- else goto state9; /* done */
-
- /* seen a complete number. machine successfully completed. whew! */
-
- state9: unput(c); /* might want that later */
- *s++ = '\0';
- return(bf);
-
- /* Uh oh. An error. Print an error and restart. */
-
- state10: printf("\n\007??");
- goto state1;
- }
-
- /* gtok() -- read a token using input(). Tokens are delimited by whitespace.
- * When '\n' is found, "\n" is returned.
- * For EOF or control characters (not '\n' or '\t') 0 is returned.
- */
- char *gtok()
- {
- static char token[20];
- register char *s,c;
-
- s = &token[0];
- loop: c=input();
- if(c==' ' || c=='\t') goto loop;
- else if(c == '\n') return("\n");
- else if(c==EOF || iscntrl(c)) return(0);
- else {
- *s++ = c;
- for(c=input(); c>' ' && c<='~'; c=input())
- *s++ = c;
- unput(c);
- *s++ = '\0';
- return(token);
- }
- }
-
- /* insline(num) -- insert num into llist with insertion sort style.
- * Replaces old lines if already in list.
- */
- struct line *insline(num)
- int num;
- {
- struct line *p,*p2,*p3;
- struct dictnode *vp;
- struct dictnode *gvadr();
- char s[12];
-
- if(lastline == LASTLINE) return(0);
- for(p=lastline; p->num > num; p--)
- /* null */ ;
- if(p->num == num) {
- if(p->code != 0) { free(p->code); p->code = 0; }
- if(p->text != 0) { free(p->text); p->text = 0; }
- }
- else { /* p->num < num */
- ++p;
- p2=lastline;
- p3= ++lastline;
- while(p2 >= p) {
- p3->num = p2->num;
- p3->code = p2->code;
- p3->text = p2->text;
- p2--;
- p3--;
- }
- p->num = num;
- p->text = p->code = 0;
- }
- sprintf(s,"LN%d",num);
- vp = gvadr(s,T_LBL);
- vp->val.lval.codelist = p;
- vp->val.lval.place = 0;
- return(p);
- }
-
- /* gvadr() -- Get variable address from vlist, with type checking.
- * This routine allows numerous copies of same name as long as
- * all copies have different types. Probably doesnt matter since
- * the parser does the type checking.
- */
- struct dictnode *gvadr(s,ty)
- char *s;
- int ty;
- {
- register int i;
- register int qual; /* type qualifier */
-
- for(i=0; vlist[i].name!=0 && i<VLSIZ; i++)
- if(vlist[i].type_of_value==ty && strcmp(s,vlist[i].name)==0)
- break; /* match found */
- if(i >= VLSIZ) {
- fprintf(stderr,"gvadr: out of room in variable list for %s\n",s);
- exit(1);
- }
- if(vlist[i].name == 0) { /* not on list, enter it */
- vlist[i].name = myalloc(strlen(s)+1);
- strcpy(vlist[i].name,s);
- vlist[i].val.rval = 0;
- vlist[i].type_of_value = ty;
- if(ty&T_QMASK == Q_ARY)
- vlist[i].val.arval = myalloc(13*sizeof(union value));
- }
- return(&vlist[i]);
- }
-
- /* getplace() -- get a pointer to place of value for vlist entry on top of stack
- * For arrays, getplace() expects the indexes to be on the stack as well.
- * The parser should properly arrange for this to happen.
- */
- union value *getplace(dp)
- struct dictnode *dp;
- {
- int qual;
- union value ind,*place;
-
- qual = dp->type_of_value&T_QMASK;
- if(qual == Q_ARY) {
- ind = pop();
- mpop();
- place = & dp->val.arval[ind.ival+2];
- }
- else
- place = & dp->val;
- return(place);
- }
-
- /* gladr() -- get address of llist entry, given the line number.
- */
- struct line *gladr(lnum)
- unsigned lnum;
- {
- register struct line *q;
- register int num;
-
- num = lnum;
- for(q= &llist[0]; q->num!=num && q->num!=MAXLN ; q++)
- ;
- if(q->num == MAXLN) return(0);
- /* else */
- if(q->code==0 && q->text==0) return(0); /* fake line */
- /* else */
- return(q); /* found place */
- }
-
- /* gllentry() -- Given an address for a code list, return llist entry which
- * has matching code list address.
- */
- struct line *gllentry(l)
- int **l;
- {
- register int llp;
-
- for(llp=0; llist[llp].num != MAXLN; llp++)
- if(llist[llp].code == l)
- return(&llist[llp]);
-
- return(0); /* such an entry not found */
- }
-
- /* glist() -- read rest of line as a code list, return the corresponding
- * code list.
- */
- int **glist()
- {
- register char *s;
- int (*codestring[100])();
- int lp,(**l)();
- register int i;
-
- lp=0;
- for(s=gtok(); s!=0 && strcmp(s,"\n")!=0; s=gtok()) {
- for(i=0; wlist[i].name!=0; i++)
- if(strcmp(wlist[i].name,s)==0)
- break;
- if(wlist[i].name == 0) {
- fprintf(stderr,"unknown name %s\n",s);
- exit(1);
- }
- if(wlist[i].funct == 0) {
- fprintf(stderr,"glist: no function for %s at %o\n",s,&wlist[i]);
- exit(1);
- }
- codestring[lp++] = wlist[i].funct;
- lp = (*wlist[i].funct)(codestring,lp);
- }
- codestring[lp++] = 0;
- l = myalloc(lp*2+1);
- blcpy(l,codestring,lp*2);
- return(l);
- }
-
- /* rprg -- read in a bunch of lines, put them in program buffer.
- */
- rprg()
- {
- char *s;
- int ln;
- struct line *pl;
-
- for(s=gtok(); s!=0; s=gtok()) {
- if(strcmp(s,"line") == 0) {
- s=gtok();
- ln=atoi(s);
- pl=insline(ln);
- if(pl == 0){ fprintf(stderr,"out of room for program\n");exit(1); }
- s=myalloc(strlen(ibuf)+1);
- strcpy(s,ibuf);
- pl->text = s;
- pl->code = glist();
- }
- else { fprintf(stderr,"syntax error, no line number: %s\n",ibuf); exit(1); }
- }
- }
-
-
- interp(l,start)
- int (*l[])(),start;
- {
- int lp;
- for(lp=start+1; l[lp-1]!=0; lp++)
- lp = (*l[lp-1])(l,lp);
- return(lp);
- }
-
- /* runit() -- run the program in llist. arg- address of place to start at.
- *
- * to do a goto type action, set Thisline to llist entry PREVIOUS to
- * desired place. Set Thisp to desired index. To cause it to happen,
- * place a 0 in the code list where interp() will see it at the right
- * time.
- *
- * All this will cause runit() to run correctly, and automatically take
- * care of updating the line number pointers (Thisline and Thisp).
- */
- runit()
- {
- int ourthisp;
-
- ourthisp = Thisp;
- Thisp = 0;
- while(Thisline < lastline) {
- interp((Thisline->code),ourthisp);
- ++Thisline;
- ourthisp = Thisp;
- Thisp = 0;
- }
- }
-
- int dbg = 0; /* debugging flag. */
- main(argc,argv)
- int argc;
- char **argv;
- {
- int i,j;
- int (**l)();
-
- if(argc >= 2) {
- if((bsin=fopen(argv[1],"r")) == NULL) {
- fprintf(stderr,"main: could not open input file %s\n",argv[1]);
- exit(1);
- }
- }
- if(argc > 2) dbg = 1; /* "int file <anything>" sets debugging */
-
- /* Read the program (on file bsin) and compile it to the executable code. */
- rdlin(bsin);
- status = M_COMPILE;
- rprg();
- if(bsin != stdin) fclose(bsin);
- bsin = stdin; /* make sure it is stdin for execution */
- iptr = 0;
- ibuf[iptr] = 0; /* make the input buffer empty. */
-
- /* Scan through the compiled code, make sure things point to where
- * they are supposed be pointing to, etc.
- */
- status = M_FIXUP;
- Thisline = &llist[0];
- while(Thisline < lastline) {
- interp((Thisline->code),0);
- ++Thisline;
- }
-
- status = M_EXECUTE;
- dlp = 0; /* set it back to beginning of list */
- Thisline = &llist[0];
- Thisp = 0;
- runit();
- }
-