home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume2 / basic / part3 / bs2 / bsint.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  11.8 KB  |  525 lines

  1. /* bsint.c -- main part of interpretor.
  2.  */
  3.  
  4. #include "bsdefs.h"
  5.  
  6. int (*_null[])() = { 0,0 };
  7.  
  8. struct line llist[NUMLINES] = {
  9.     0, _null, "",
  10.     MAXLN, _null, ""
  11. };
  12.  
  13. struct line *lastline = &llist[1];
  14. struct line *Thisline = &llist[0];
  15. int Thisp = 0;
  16.  
  17. struct dictnode vlist[VLSIZ];
  18.  
  19.  
  20. /* bslash() -- have seen '\', use input() to say what is actually wanted.
  21.  */
  22. char bslash()
  23. {
  24.     char text[8];
  25.     register char *s,c;
  26.     int v;
  27.  
  28.     c=input();
  29.     if(c == 'n') c='\n';
  30.     else if(c == 't') c='\t';
  31.     else if(c == 'b') c='\b';
  32.     else if(c == 'r') c='\r';
  33.     else if(c == 'f') c='\f';
  34.     else if(c>='0' && c<='7') { /* octal digit string */
  35.     s = &text[0];
  36.     *s++ = c;
  37.     c=input();
  38.     while(c>='0' && c<='7') {
  39.         *s++ = c;
  40.         c=input();
  41.     }
  42.     *s++ = '\0';
  43.     sscanf(text,"%o",&v);
  44.     c = (char) v;
  45.     }
  46.     else if(c=='\n') rdlin(bsin);
  47.     return(c);
  48. }
  49.  
  50.  
  51. /* scon_in() -- read in a string constant using input.
  52.  *    Format of an scon is either a quoted string, or a sequence
  53.  *    of characters ended with a seperator (' ', '\t' or '\n' or ',').
  54.  *
  55.  *    In either mode, you can get funny characters into the string by
  56.  *    "quoting" them with a '\'.
  57.  *
  58.  * scon_in() uses myalloc() to create space to store the string in.
  59.  */
  60. char *scon_in()
  61. {
  62.     register char c,*s;
  63.     static char text [80];
  64.  
  65.     s = &text[0];
  66.  
  67. /* beginning state, skip seperators until something interesting comes along */
  68.  
  69. l1: c=input();
  70.     if(c == '"') goto l2;
  71.     else if(c=='\n' || c=='\0') {
  72.     rdlin(bsin);
  73.     goto l1;
  74.     }
  75.     else if(c==' ' || c=='\t' || c==',') goto l1;
  76.     else goto l3;
  77.  
  78. /* have skipped unwanted material, seen a '"', read in a quoted string */
  79.  
  80. l2: c=input();
  81.     if(c == '\n') {
  82.     fprintf(stderr,"scon_in: unterminated string\n");
  83.     exit(1);
  84.     }
  85.     else if(c == '\\') { *s++ = bslash(bsin); goto l2; }
  86.     else if(c == '"')
  87.     if((c=input()) == '"') {
  88.         *s++ = '"';
  89.         goto l2;
  90.     }
  91.     else goto done;
  92.     else { *s++ = c; goto l2; }
  93.  
  94. /* skipped unwanted, seen something interesting, not '"', gather until sep */
  95.  
  96. l3: *s++ = c;
  97.     c=input();
  98.     if(c == '\\') { c = bslash(bsin); goto l3; }
  99.     else if(c==' ' || c=='\t' || c==',' || c=='\n') goto done;
  100.     else goto l3;
  101.  
  102. /* final state (if machine finished ok.) */
  103.  
  104. done: unput(c);
  105.     *s++ = '\0';
  106.     s=myalloc(strlen(text)+1);
  107.     strcpy(s,text);
  108.     return(s);
  109. }
  110.  
  111. /* int_in() -- tokenizer routine for inputting a number.
  112.  * int_in() returns a pointer to a static data area.  This area gets 
  113.  * overwritten with each call to int_in so use the data before calling
  114.  * int_in() again.
  115.  */
  116. char * int_in()
  117. {
  118.     register char c,*s;
  119.     static char text[20];
  120.  
  121.     s = &text[0];
  122.  
  123. /* beginning state, skip junk until either '-' or ['0'-'9'] comes along */
  124.  
  125. l1: c=input();
  126.     if(c>='0' && c<='9') goto l3;
  127.     else if(c == '-') goto l2;
  128.     else {
  129.     if(c=='\n' || c=='\0') rdlin(bsin);
  130.     goto l1;
  131.     }
  132.  
  133. /* skipped junk, seen '-', gather it and make sure next char is a digit */
  134.  
  135. l2: *s++ = c;
  136.     c=input();
  137.     if(c==' ' || c=='\t') goto l2; /* allow white between sign and digit */
  138.     else if(c>='0' && c<='9') goto l3;
  139.     else { /* seen something not allowed. */
  140.     s = &text[0];
  141.     printf("\n\007??");
  142.     goto l1; /* restart machine */
  143.     }
  144.  
  145. /* skipped junk, seen a digit, gather until a non-digit appears */
  146.  
  147. l3: *s++ = c;
  148.     c=input();
  149.     if(c>='0' && c<='9') goto l3;
  150.     else {
  151.     /* have reached successful conclusion to machine. */
  152.     unput(c);
  153.     *s++ = '\0';
  154.     return(text);
  155.     }
  156. }
  157.  
  158. /* real_in() -- read in a floating point number using input().
  159.  *
  160.  * real_in() returns a pointer to a static data area.  This data area
  161.  * gets overwritten with each call to real_in(), so use it quickly.
  162.  */
  163. char *real_in()
  164. {
  165.     register char *s,c;
  166.     static char bf[30];
  167.  
  168.     s = &bf[0];
  169.  
  170. /* starting state.  loops back until something interesting seen */
  171.  
  172. state1:    c=input();
  173.     if(c == '-') goto state3;
  174.     else if(c>='0' && c<='9') goto state2;
  175.     else if(c == '.') goto state4;
  176.     else {
  177.         if(c=='\n' || c=='\0') rdlin(bsin);
  178.         goto state1;
  179.     }
  180.  
  181. /* seen a digit.  gather all digits following. */
  182.  
  183. state2: *s++ = c;
  184.     c=input();
  185.     if(c>='0' && c<='9') goto state2;
  186.     else if(c == '.') goto state4;
  187.     else goto state9;    /* done */
  188.  
  189. /* seen a sign character before start of number.  loop back for whitespace. */
  190.  
  191. state3: *s++ = c;
  192. state3_a: c=input();
  193.     if(c==' ' || c=='\t') goto state3_a;
  194.     else if(c>='0' && c<='9') goto state2;
  195.     else if(c == '.') goto state4;
  196.     else goto state10;    /* error, had a sign so we have to have digs. */
  197.  
  198. /* seen digit(s) and a decimal point. looking for more digs or ('e'|'E') */
  199.  
  200. state4: *s++ = c;
  201.     c=input();
  202.     if(c>='0' && c<='9') goto state5;
  203.     else if(c=='e' || c=='E') goto state6;
  204.     else goto state9;    /* done */
  205.  
  206. /* seen (digs '.' dig).  look for more digs or ('e'|'E'). */
  207.  
  208. state5:    *s++ = c;
  209.     c=input();
  210.     if(c=='e' || c=='E') goto state6;
  211.     else if(c>='0' && c<='9') goto state5;
  212.     else goto state9;
  213.  
  214. /* seen (digs '.' digs (e|E)). looking for sign or digs, else error. */
  215.  
  216. state6: *s++ = c;
  217.     c=input();
  218.     if(c=='+' || c=='-') goto state7;
  219.     else if(c>='0' && c<='9') goto state8;
  220.     else goto state10;    /* error */
  221.  
  222. /* seen (digs '.' digs (e|E) sign). looking for digs, else error. */
  223.  
  224. state7: *s++ = c;
  225.     c=input();
  226.     if(c>='0' && c<='9') goto state8;
  227.     else goto state10;    /* error */
  228.  
  229. /* seen (digs '.' digs (e|E) [sign] dig). looking for digs. */
  230.  
  231. state8: *s++ = c;
  232.     c=input();
  233.     if(c>='0' && c<='9') goto state8;
  234.     else goto state9;    /* done */
  235.  
  236. /* seen a complete number.  machine successfully completed.  whew! */
  237.  
  238. state9: unput(c);    /* might want that later */
  239.     *s++ = '\0';
  240.     return(bf);
  241.  
  242. /* Uh oh.  An error.  Print an error and restart. */
  243.  
  244. state10: printf("\n\007??");
  245.     goto state1;
  246. }
  247.  
  248. /* gtok() -- read a token using input().  Tokens are delimited by whitespace.
  249.  *    When '\n' is found, "\n" is returned.
  250.  *    For EOF or control characters (not '\n' or '\t') 0 is returned.
  251.  */
  252. char *gtok()
  253. {
  254.     static char token[20];
  255.     register char *s,c;
  256.  
  257.     s = &token[0];
  258. loop: c=input();
  259.     if(c==' ' || c=='\t') goto loop;
  260.     else if(c == '\n') return("\n");
  261.     else if(c==EOF || iscntrl(c)) return(0);
  262.     else {
  263.     *s++ = c;
  264.     for(c=input(); c>' ' && c<='~'; c=input())
  265.         *s++ = c;
  266.     unput(c);
  267.     *s++ = '\0';
  268.     return(token);
  269.     }
  270. }
  271.  
  272. /* insline(num) -- insert num into llist with insertion sort style.
  273.  *    Replaces old lines if already in list.
  274.  */
  275. struct line *insline(num)
  276. int num;
  277. {
  278.     struct line *p,*p2,*p3;
  279.     struct dictnode *vp;
  280.     struct dictnode *gvadr();
  281.     char s[12];
  282.  
  283.     if(lastline == LASTLINE) return(0);
  284.     for(p=lastline; p->num > num; p--)
  285.     /* null */ ;
  286.     if(p->num == num) {
  287.     if(p->code != 0) { free(p->code); p->code = 0; }
  288.     if(p->text != 0) { free(p->text); p->text = 0; }
  289.     }
  290.     else { /* p->num < num */
  291.     ++p;
  292.     p2=lastline;
  293.     p3= ++lastline;
  294.     while(p2 >= p) {
  295.         p3->num = p2->num;
  296.         p3->code = p2->code;
  297.         p3->text = p2->text;
  298.         p2--;
  299.         p3--;
  300.     }
  301.     p->num = num;
  302.     p->text = p->code = 0;
  303.     }
  304.     sprintf(s,"LN%d",num);
  305.     vp = gvadr(s,T_LBL);
  306.     vp->val.lval.codelist = p;
  307.     vp->val.lval.place = 0;
  308.     return(p);
  309. }
  310.  
  311. /* gvadr() -- Get variable address from vlist, with type checking.
  312.  *    This routine allows numerous copies of same name as long as
  313.  *    all copies have different types.  Probably doesnt matter since
  314.  *    the parser does the type checking.
  315.  */
  316. struct dictnode *gvadr(s,ty)
  317. char *s;
  318. int ty;
  319. {
  320.     register int i;
  321.     register int qual; /* type qualifier */
  322.  
  323.     for(i=0; vlist[i].name!=0 && i<VLSIZ; i++)
  324.     if(vlist[i].type_of_value==ty && strcmp(s,vlist[i].name)==0)
  325.         break; /* match found */
  326.     if(i >= VLSIZ) {
  327.     fprintf(stderr,"gvadr: out of room in variable list for %s\n",s);
  328.     exit(1);
  329.     }
  330.     if(vlist[i].name == 0) { /* not on list, enter it */
  331.     vlist[i].name = myalloc(strlen(s)+1);
  332.     strcpy(vlist[i].name,s);
  333.     vlist[i].val.rval = 0;
  334.     vlist[i].type_of_value = ty;
  335.     if(ty&T_QMASK == Q_ARY)
  336.         vlist[i].val.arval = myalloc(13*sizeof(union value));
  337.     }
  338.     return(&vlist[i]);
  339. }
  340.  
  341. /* getplace() -- get a pointer to place of value for vlist entry on top of stack
  342.  *    For arrays, getplace() expects the indexes to be on the stack as well.
  343.  *    The parser should properly arrange for this to happen.
  344.  */
  345. union value *getplace(dp)
  346. struct dictnode *dp;
  347. {
  348.     int qual;
  349.     union value ind,*place;
  350.  
  351.     qual = dp->type_of_value&T_QMASK;
  352.     if(qual == Q_ARY) {
  353.     ind = pop();
  354.     mpop();
  355.     place = & dp->val.arval[ind.ival+2];
  356.     }
  357.     else
  358.     place = & dp->val;
  359.     return(place);
  360. }
  361.  
  362. /* gladr() -- get address of llist entry, given the line number.
  363.  */
  364. struct line *gladr(lnum)
  365. unsigned lnum;
  366. {
  367.     register struct line *q;
  368.     register int num;
  369.  
  370.     num = lnum;
  371.     for(q= &llist[0]; q->num!=num && q->num!=MAXLN ; q++)
  372.         ;
  373.     if(q->num == MAXLN) return(0);
  374.     /* else */
  375.     if(q->code==0 && q->text==0) return(0); /* fake line */
  376.     /* else */
  377.     return(q); /* found place */
  378. }
  379.  
  380. /* gllentry() -- Given an address for a code list, return llist entry which
  381.  *    has matching code list address.
  382.  */
  383. struct line *gllentry(l)
  384. int **l;
  385. {
  386.     register int llp;
  387.  
  388.     for(llp=0; llist[llp].num != MAXLN; llp++)
  389.     if(llist[llp].code == l)
  390.         return(&llist[llp]);
  391.  
  392.     return(0);    /* such an entry not found */
  393. }
  394.  
  395. /* glist() -- read rest of line as a code list, return the corresponding
  396.  *    code list.
  397.  */
  398. int **glist()
  399. {
  400.     register char *s;
  401.     int (*codestring[100])();
  402.     int lp,(**l)();
  403.     register int i;
  404.  
  405.     lp=0;
  406.     for(s=gtok(); s!=0 && strcmp(s,"\n")!=0; s=gtok()) {
  407.     for(i=0; wlist[i].name!=0; i++)
  408.         if(strcmp(wlist[i].name,s)==0)
  409.         break;
  410.     if(wlist[i].name == 0) {
  411.         fprintf(stderr,"unknown name %s\n",s);
  412.         exit(1);
  413.     }
  414.     if(wlist[i].funct == 0) {
  415.         fprintf(stderr,"glist: no function for %s at %o\n",s,&wlist[i]);
  416.         exit(1);
  417.     }
  418.     codestring[lp++] = wlist[i].funct;
  419.     lp = (*wlist[i].funct)(codestring,lp);
  420.     }
  421.     codestring[lp++] = 0;
  422.     l = myalloc(lp*2+1);
  423.     blcpy(l,codestring,lp*2);
  424.     return(l);
  425. }
  426.  
  427. /* rprg -- read in a bunch of lines, put them in program buffer.
  428.  */
  429. rprg()
  430. {
  431.     char *s;
  432.     int ln;
  433.     struct line *pl;
  434.  
  435.     for(s=gtok(); s!=0; s=gtok()) {
  436.     if(strcmp(s,"line") == 0) {
  437.         s=gtok();
  438.         ln=atoi(s);
  439.         pl=insline(ln);
  440.         if(pl == 0){ fprintf(stderr,"out of room for program\n");exit(1); }
  441.         s=myalloc(strlen(ibuf)+1);
  442.         strcpy(s,ibuf);
  443.         pl->text = s;
  444.         pl->code = glist();
  445.     }
  446.     else { fprintf(stderr,"syntax error, no line number: %s\n",ibuf); exit(1); }
  447.     }
  448. }
  449.  
  450.  
  451. interp(l,start)
  452. int (*l[])(),start;
  453. {
  454.     int lp;
  455.     for(lp=start+1; l[lp-1]!=0; lp++)
  456.     lp = (*l[lp-1])(l,lp);
  457.     return(lp);
  458. }
  459.  
  460. /* runit() -- run the program in llist.  arg- address of place to start at.
  461.  *
  462.  * to do a goto type action, set Thisline to llist entry PREVIOUS to 
  463.  * desired place.  Set Thisp to desired index.  To cause it to happen,
  464.  * place a 0 in the code list where interp() will see it at the right
  465.  * time.
  466.  *
  467.  * All this will cause runit() to run correctly, and automatically take
  468.  * care of updating the line number pointers (Thisline and Thisp).
  469.  */
  470. runit()
  471. {
  472.     int ourthisp;
  473.  
  474.     ourthisp = Thisp;
  475.     Thisp = 0;
  476.     while(Thisline < lastline) {
  477.     interp((Thisline->code),ourthisp);
  478.     ++Thisline;
  479.     ourthisp = Thisp;
  480.     Thisp = 0;
  481.     }
  482. }
  483.  
  484. int dbg = 0;    /* debugging flag. */
  485. main(argc,argv)
  486. int argc;
  487. char **argv;
  488. {
  489.     int i,j;
  490.     int (**l)();
  491.  
  492.     if(argc >= 2) {
  493.     if((bsin=fopen(argv[1],"r")) == NULL) {
  494.         fprintf(stderr,"main: could not open input file %s\n",argv[1]);
  495.         exit(1);
  496.     }
  497.     }
  498.     if(argc > 2) dbg = 1;    /* "int file <anything>" sets debugging */
  499.  
  500.     /* Read the program (on file bsin) and compile it to the executable code. */
  501.     rdlin(bsin);
  502.     status = M_COMPILE;
  503.     rprg();
  504.     if(bsin != stdin) fclose(bsin);
  505.     bsin = stdin;    /* make sure it is stdin for execution */
  506.     iptr = 0;
  507.     ibuf[iptr] = 0;    /* make the input buffer empty. */
  508.  
  509.     /* Scan through the compiled code, make sure things point to where
  510.      * they are supposed be pointing to, etc.
  511.      */
  512.     status = M_FIXUP;
  513.     Thisline = &llist[0];
  514.     while(Thisline < lastline) {
  515.     interp((Thisline->code),0);
  516.     ++Thisline;
  517.     }
  518.  
  519.     status = M_EXECUTE;
  520.     dlp = 0;    /* set it back to beginning of list */
  521.     Thisline = &llist[0];
  522.     Thisp = 0;
  523.     runit();
  524. }
  525.