home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 286_02 / interp.c < prev    next >
Text File  |  1989-05-25  |  16KB  |  586 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <setjmp.h>
  4. #include <stdarg.h>
  5.  
  6. /*==============================================================*
  7.  *                                                              *
  8.  *  This program is used to interpret GRAD functions in         *
  9.  *      restricted C syntax of function call.                   *
  10.  *  The method used is recursive descend.                       *
  11.  *                                                              *
  12.  *==============================================================*/
  13.  
  14. #define unreadc(ch) ungetc(ch,infile)
  15.  
  16. /* maximum number of parameter for a single function */
  17. #define MAXPARM 9
  18.  
  19. #define Boolean int
  20. #define TRUE 1
  21. #define FALSE 0
  22. #define ERROR (-1)
  23.  
  24. enum Ptype {
  25.     UNDEFINED, INTG, STRG
  26. };
  27.  
  28. struct funcdesc {
  29.     char *name;
  30.     enum Ptype rettype;
  31.     int nuparm;
  32.     enum Ptype parmstype[MAXPARM];
  33. };
  34.  
  35. /* The function names must arrange in ascending order */
  36. struct funcdesc FUNCTIONS[] =
  37.     { { "Arc1",     UNDEFINED, 4, { INTG, INTG, INTG, INTG } } ,
  38.       { "Arc2",     UNDEFINED, 5, { INTG, INTG, INTG, INTG, INTG } },
  39.       { "ArcPoint", UNDEFINED, 4, { INTG, INTG, INTG, INTG } },
  40.       { "BlockCopy",  INTG, 8,
  41.                     { INTG, INTG, INTG, INTG, INTG, INTG, INTG, INTG } },
  42.       { "BlockLoad",  INTG, 3, { INTG, INTG, STRG } },
  43.       { "BlockSave",  UNDEFINED, 5, { INTG, INTG, STRG, INTG, INTG } },
  44.       { "Box",      UNDEFINED, 6, { INTG, INTG, INTG, INTG, INTG, INTG } } ,
  45.       { "Circle",   UNDEFINED, 3, { INTG, INTG, INTG } } ,
  46.       { "CreateFrame", INTG, 2, { INTG, INTG } } ,
  47.       { "Dot",      UNDEFINED, 2, { INTG, INTG } } ,
  48.       { "Draw",     UNDEFINED, 3, { STRG, INTG, INTG } },
  49.       { "Earc1",    UNDEFINED, 5, { INTG, INTG, INTG, INTG, INTG } } ,
  50.       { "Earc2",    UNDEFINED, 6, { INTG, INTG, INTG, INTG, INTG, INTG } },
  51.       { "Ellipse",  UNDEFINED, 4, { INTG, INTG, INTG, INTG } } ,
  52.       { "EnvRsto",  UNDEFINED, 2, { INTG, INTG } },
  53.       { "EnvSave",  INTG, 1, { INTG } },
  54.       { "FillCircle", UNDEFINED, 3, { INTG, INTG, INTG } },
  55.       { "FillEllipse",UNDEFINED, 4, { INTG, INTG, INTG, INTG } },
  56.       { "HorzLine", UNDEFINED, 4, { INTG, INTG, INTG, INTG } } ,
  57.       { "Line",     UNDEFINED, 4, { INTG, INTG, INTG, INTG } } ,
  58.       { "LoadFont", INTG, 1, { STRG } } ,
  59.       { "NextXY",   UNDEFINED, 2, { INTG, INTG } },
  60.       { "PatternFill", UNDEFINED, 4, { INTG, INTG, STRG, INTG } },
  61.       { "PlotType", INTG, 1, { INTG } } ,
  62.       { "PrintFrame", UNDEFINED, 5, { INTG, STRG, INTG, INTG, INTG } } ,
  63.       { "PrintPage",  UNDEFINED, 0 },
  64.       { "ReadStr",    UNDEFINED, 7,
  65.                           { STRG, INTG, INTG, INTG, INTG, INTG, INTG } },
  66.       { "Rectangle",  UNDEFINED, 4, { INTG, INTG, INTG, INTG } } ,
  67.       { "RelOrg",   UNDEFINED, 2, { INTG, INTG } } ,
  68.       { "RemvFont", INTG, 1, { INTG } } ,
  69.       { "RemvFrame", INTG, 1, { INTG } } ,
  70.       { "ResetWin", UNDEFINED, 0 } ,
  71.       { "SelectFont",  INTG, 1, { INTG } },
  72.       { "SelectFrame", INTG, 1, { INTG } } ,
  73.       { "SetOrg",   UNDEFINED, 2, { INTG, INTG } } ,
  74.       { "SetStyle", UNDEFINED, 1, { INTG } } ,
  75.       { "SetWin",   UNDEFINED, 4, { INTG, INTG, INTG, INTG } } ,
  76.       { "SolidFill",   UNDEFINED, 2, { INTG, INTG } },
  77.       { "VertLine", UNDEFINED, 4, { INTG, INTG, INTG, INTG } },
  78.       { "WriteStr", UNDEFINED, 7, { INTG, INTG, INTG, INTG, STRG, INTG, INTG }},
  79.       { "XHLine",   INTG, 5, { INTG, INTG, INTG, INTG, INTG } }
  80.  };
  81.  
  82. #define NFUNC (sizeof(FUNCTIONS) / sizeof(struct funcdesc))
  83.  
  84. char *ERRMSG[]= {
  85.     "Undefined Error Number\n",
  86.     "Variable/Function name expected\n",
  87.     "Variable name %s not found\n",
  88.     "Function name or expression expected\n",
  89.     "Function name %s not found\n",
  90.     "'(' expected after function name\n",
  91.     "Type if parameter %d is different from definition\n",
  92.     "')' expected after the parameters of a function\n",
  93.     "Less parameter than expected\n",
  94.     "End of string not detected before end of line\n",
  95.     "',' expected after a parameter\n",
  96.     "'C' or 'L' expected after '['\n",
  97.     "']' expected after a line or column specification\n",
  98.     "Identifier Expected\n"
  99. };
  100.  
  101. #define NUOFERROR (sizeof(ERRMSG) / sizeof(char *))
  102.  
  103. char LINE[160];
  104.  
  105. int PATTERN[]={
  106.     0x5555, 0xaaaa, 0x5555, 0xaaaa,
  107.     0x5555, 0xaaaa, 0x5555, 0xaaaa,
  108.     0x5555, 0xaaaa, 0x5555, 0xaaaa,
  109.     0x5555, 0xaaaa, 0x5555, 0xaaaa,
  110.     0x8888, 0x4444, 0x2222, 0x1111,
  111.     0x8888, 0x4444, 0x2222, 0x1111,
  112.     0x8888, 0x4444, 0x2222, 0x1111,
  113.     0x8888, 0x4444, 0x2222, 0x1111,
  114.     0x1111, 0x2222, 0x4444, 0x8888,
  115.     0x1111, 0x2222, 0x4444, 0x8888,
  116.     0x1111, 0x2222, 0x4444, 0x8888,
  117.     0x1111, 0x2222, 0x4444, 0x8888
  118. };
  119.  
  120. struct pval {
  121.     enum Ptype parmtype;
  122.     union {
  123.         int u_int;
  124.         char *u_strg;
  125.     } v;
  126. };
  127.  
  128. struct pval RETVAL, *expr();
  129.  
  130. char IDNAME[12], CHARS[512], *PSPTR;
  131.  
  132. #define NUOFVAR 21
  133.  
  134. int nuofvar=NUOFVAR;
  135. char VARNAME[NUOFVAR][12]={
  136.     "pattern1", "pattern2", "pattern3",
  137.     "line",
  138.     "font1", "font2", "font3", "font4",
  139.     "frame1", "frame2", "frame3",
  140.     "temp1", "temp2", "temp3",
  141.     "x1", "x2", "y1", "y2",
  142.     "env1", "env2", "env3"
  143. };
  144.  
  145. struct pval VARTABLE[NUOFVAR];
  146.  
  147. int COL_OFFSET=0, ROW_OFFSET=0, LINE_HEIGHT=12, CHAR_WIDTH=12;
  148.  
  149. jmp_buf EOF_JMP, SYNERR_JMP;
  150.  
  151. int EOF_FLAG=0;
  152.  
  153. FILE *infile;
  154.  
  155. main(argc,argv)
  156. int argc;
  157. char *argv[];
  158. {
  159.     int ret;
  160.     FILE *fopen();
  161.  
  162.     if (argc <= 1) {
  163.         fprintf(stderr,"Usage: interp commandfile\n");
  164.         exit(1);
  165.     }
  166.     if ((infile=fopen(*(++argv), "r")) == (FILE *) NULL) {
  167.         fprintf(stderr,"interp: File not found\n");
  168.         exit(1);
  169.     }
  170.     GRADinit();         /* GRAD initialization function */
  171.     initvars();         /* initialize internal variables */
  172.     setgraph();         /* set graphics mode */
  173.  
  174.     if (setjmp(EOF_JMP) != 0) {
  175.         /* return here on End_Of_File */
  176.         fclose(infile);
  177.         if (EOF_FLAG) { 
  178.             printf("interp: Unexpected End Of File !\n");
  179.         }
  180.         getch();
  181.         settext();
  182.         cleanup(EOF_FLAG);
  183.         exit(0);
  184.     }
  185.     setjmp(SYNERR_JMP);
  186.     /* return here on syntax error */
  187.     for (;;) {
  188.         EOF_FLAG=0;
  189.         stmt();
  190.     }
  191. }
  192.  
  193. /*------------------------------------------------------*
  194.  *    read a single character from input file.          *
  195.  *    A string of comment is treated as a single space  *
  196.  *    Comments can be nested.                           *
  197.  *------------------------------------------------------*/
  198. readc0()
  199. {
  200.     int ch;
  201.  
  202.     if ((ch=getc(infile)) == EOF) {
  203.         longjmp(EOF_JMP,1);
  204.     }
  205.     if (ch != '/') return(ch);
  206.     if ((ch=getc(infile)) == EOF) {
  207.         longjmp(EOF_JMP,1);
  208.     }
  209.     if (ch != '*') {
  210.         ungetc(ch,infile);
  211.         return('/');
  212.     }
  213.     /* begining of comment */
  214.     for (;;) {
  215.         if ((ch=readc0()) == '*') {
  216.             while((ch=readc0()) == '*') ;
  217.             if (ch=='/') return(' ');
  218.         }
  219.     }
  220. }
  221.  
  222. /* skip all control characters except tab (0x09) and return (0x0d) */
  223. /* but they will be returned as space (0x20)                       */
  224. readc1()
  225. {
  226.     int ch;
  227.  
  228.     do {
  229.         ch=readc0();
  230.         if (isspace(ch)) return(' ');
  231.     } while (ch < 0x20);
  232.     return(ch);
  233. }
  234.  
  235. /* read first non-blank character from input file */
  236. readc2()
  237. {
  238.     int ch;
  239.  
  240.     do {
  241.         ch=readc1();
  242.     } while (ch==' ');
  243.     EOF_FLAG=1;
  244.     return(ch);
  245. }
  246.  
  247. /* procdure to interpret a statement */
  248. /* { } means optional, | means or
  249.  
  250.    STMT := [ VARIABLE = ] FUNCTION
  251.    VARIABLE := identifier
  252.    FUNCTION := identifier ( PARAMETERS ) ;
  253.    PARAMETERS := PARAMETER , PARAMETERS | PARAMETER
  254.    PARAMETER := EXPRESSION
  255. */
  256. stmt()
  257. {
  258.     int ch, varidx,funcidx, nuparmoffunc, nparm;
  259.     struct pval *valptr, parmlist[MAXPARM];
  260.  
  261.     PSPTR=CHARS;
  262.     varidx=-1;    /* init */
  263.     if (!identifier()) {   /* is first token an identifier */
  264.         synerr(1);         /* syntax error 1 */
  265.     }
  266.     ch=readc2();
  267.     if (ch=='=') {
  268.         if ((varidx=findvar(IDNAME))==ERROR) {
  269.             synerr(2,IDNAME);
  270.         }
  271.         if (!identifier()) {
  272.             valptr=expr();
  273.             if (valptr->parmtype == UNDEFINED) {
  274.                 synerr(3);
  275.             } else {
  276.                 VARTABLE[varidx]=*valptr;
  277.                 goto endofstmt;
  278.             }
  279.         }
  280.         ch=readc2();
  281.     }
  282.     if ((funcidx=findfunc(IDNAME))==ERROR) {
  283.         synerr(4,IDNAME);
  284.     }
  285.     if (ch!='(') {
  286.         synerr(5);
  287.     }
  288.     if ((nuparmoffunc=FUNCTIONS[funcidx].nuparm) == 0) {
  289.         ch=readc2();
  290.     } else {
  291.         ch=',';
  292.     }
  293.     for (nparm=0; nparm<nuparmoffunc; nparm++) {
  294.         if (ch != ',') {
  295.             synerr(10);
  296.         }
  297.         valptr=expr();
  298.         if (valptr->parmtype == UNDEFINED) {
  299.             synerr(8);
  300.         }
  301.         if (valptr->parmtype != FUNCTIONS[funcidx].parmstype[nparm]) {
  302.             synerr(6,nparm+1);
  303.         }
  304.         parmlist[nparm]=*valptr;
  305.         ch=readc2();
  306.     }
  307.     if (ch != ')') {
  308.         synerr(7);
  309.     }
  310.     /* execute the functions by pushing the parameters onto stack */
  311.     /* and then call indirectly using funcidx                     */
  312.     execfunc(funcidx, FUNCTIONS[funcidx].nuparm, parmlist,
  313.              FUNCTIONS[funcidx].rettype, &RETVAL);
  314.     if (varidx>=0) {
  315.         VARTABLE[varidx]=RETVAL; /* assign the retugn value to the
  316.                                     variable */
  317.     }
  318. endofstmt:
  319.     ch=readc2();
  320.     if (ch!=';') {
  321.         printf("Warning: Semicolon ';' expected. Assuming present\n");
  322.         unreadc(ch);
  323.     }
  324. }
  325.  
  326. /* try read an identifier and put the name in IDNAME */
  327. /* if identifier not found, return FALSE else return TRUE */
  328. Boolean identifier()
  329. {
  330.     int ch, count;
  331.  
  332.     if (!isalpha(ch=readc2())) {
  333.         IDNAME[0]='\0';
  334.         unreadc(ch);
  335.         return(FALSE);
  336.     }
  337.     count=0;
  338.     do {
  339.         IDNAME[count++]=ch;
  340.         ch=readc1();
  341.     } while (isalnum(ch));
  342.     unreadc(ch);
  343.     IDNAME[count]='\0';
  344.     return(TRUE);
  345. }
  346.  
  347. /* find the variable in the variable table and return the index if found */
  348. /* else return ERROR */
  349. findvar(name)
  350. char *name;
  351. {
  352.     int loop;
  353.  
  354.     for (loop=0; loop<nuofvar; loop++) {
  355.         if (strcmp(name,VARNAME[loop])==0) return(loop);
  356.     }
  357.     return(ERROR);
  358. }
  359.  
  360. /* find the function in the function table, return index if found */
  361. /* else return ERROR */
  362. findfunc(name)
  363. char *name;
  364. {
  365.     int start, end, current, ret;
  366.  
  367.     for (start=0, end=NFUNC; start != end ; ) {
  368.         current=(start+end)>>1;
  369.         if ((ret=strcmp(name,FUNCTIONS[current].name)) == 0) {
  370.             return(current);
  371.         } else if (ret > 0) {
  372.             start=current+1;
  373.         } else {
  374.             end=current;
  375.         }
  376.     }
  377.     return(ERROR);
  378. }
  379.  
  380.  
  381. /* { } means optional, | means or
  382.  
  383.    EXPRESSION := NUMBER | STRING | VARIABLE | & VARIABLE | COLUMN | LINE
  384.    NUMBER := +NATURAL | -NATURAL
  385.    NATURAL := 0xHHHH | decimal digits
  386.    STRINGS := "character string"
  387.    H := decimal digits | A | B | C | D | E | F | a | b | c | d | e | f
  388.    COLUMN := [ C NATURAL { , NATURAL } ]
  389.    LINE := [ L NATURAL { , NATURAL } ]
  390. */
  391. struct pval *expr()
  392. {
  393.     int ch, number, sign, varidx, addrflag;
  394.  
  395.     RETVAL.parmtype=UNDEFINED;
  396.     number=sign=addrflag=0;
  397.     ch=readc2();
  398.     if (isdigit(ch)) {
  399. getnum:
  400.         if (ch=='0') {
  401.             ch=readc1();
  402.             if (toupper(ch)=='X') {
  403.                 ch=readc1();
  404.                 while(isxdigit(ch)) {
  405.                     number=(number<<4) | ((ch-(isalpha(ch) ? 7:0)) & 0x0f);
  406.                     ch=readc1();
  407.                 }
  408.             } else {
  409.                 number=getint(&ch);
  410.             }
  411.         } else {
  412.             number=getint(&ch);
  413.         }
  414.         unreadc(ch);
  415.         RETVAL.parmtype=INTG;
  416.         RETVAL.v.u_int=sign ? -number:number;
  417.     } else if (ch=='+') {
  418.         ch=readc1();
  419.         goto getnum;
  420.     } else if (ch=='-') {
  421.         sign=1;
  422.         ch=readc1();
  423.         goto getnum;
  424.     } else if (ch=='"') {
  425.         RETVAL.parmtype=STRG;
  426.         RETVAL.v.u_strg=PSPTR;
  427.         for (;;) {
  428.         if ((ch=getc(infile)) == EOF) {
  429.             longjmp(EOF_JMP,1);
  430.         }
  431.             if (ch=='\n') {
  432.                 synerr(9);
  433.             }
  434.             if (ch=='"') break;
  435.             *PSPTR++ = ch; /* put the string into string pool */
  436.         }
  437.         *PSPTR++ = '\0';
  438.     } else if (ch=='&') {
  439.         addrflag=1;
  440.         goto ident;
  441.     } else if (ch=='[') {
  442.         ch=readc2();
  443.         if (ch=='L' || ch=='l') {
  444.             ch=readc2();
  445.             number=getint(&ch);
  446.             if (number) number--;
  447.             number=number*LINE_HEIGHT+ROW_OFFSET;
  448.         } else if (ch=='C' || ch=='c') {
  449.             ch=readc2();
  450.             number=getint(&ch);
  451.             if (number) number--;
  452.             number=number*CHAR_WIDTH+COL_OFFSET;
  453.         } else {
  454.             synerr(11);
  455.         }
  456.         if (ch==',') {
  457.             ch=readc2();
  458.             number+=getint(&ch);
  459.         }
  460.         if (ch!=']') {
  461.             synerr(12);
  462.         }
  463.         RETVAL.parmtype=INTG;
  464.         RETVAL.v.u_int=number;  
  465.     } else if (isalpha(ch)) {
  466.         unreadc(ch);
  467. ident:
  468.         if (!identifier()) synerr(13);
  469.         if ((varidx=findvar(IDNAME)) == ERROR) {
  470.             synerr(2,IDNAME);
  471.         }
  472.         RETVAL=VARTABLE[varidx];
  473.         if (addrflag) {
  474.             RETVAL.parmtype=VARTABLE[varidx].parmtype=INTG;
  475.             RETVAL.v.u_int=(int) &VARTABLE[varidx].v.u_int;
  476.         }
  477.     } else if ((ch==',') || (ch==')')) {
  478.         /* empty expression, assume equal to 0 */
  479.         unreadc(ch);
  480.         RETVAL.parmtype=INTG;
  481.         RETVAL.v.u_int=0;
  482.     }
  483.     return(&RETVAL);
  484. }
  485.  
  486. /* syntax error handling */
  487. synerr(errno)
  488. int errno;
  489. {
  490.     va_list arg_ptr;
  491.     int ch;
  492.  
  493.     va_start(arg_ptr, errno);
  494.     if ((errno >= NUOFERROR) || (errno<0)) {
  495.         errno=0;
  496.     }
  497.     vprintf(ERRMSG[errno], arg_ptr);
  498.     va_end(arg_ptr);
  499.     /* skip until semicolon ';' is found */
  500.     for(;;) {
  501.         ch=readc2();
  502.         if (ch=='"') {
  503.             do {
  504.                if ((ch=getc(infile)) == EOF) {
  505.                        longjmp(EOF_JMP,1);
  506.                    }
  507.             } while (ch!='"');
  508.         }
  509.         if (ch==';') {
  510.             longjmp(SYNERR_JMP,1);
  511.         }
  512.     }
  513. }
  514.  
  515. getint(ch)
  516. int *ch;
  517. {
  518.     int number;
  519.  
  520.     number=0;
  521.     while (isdigit(*ch)) {
  522.         number=number*10 + (*ch & 0x0f);
  523.         *ch=readc1();
  524.     }
  525.     return(number);
  526. }
  527.  
  528. /* function for testing only
  529. execfunc(current, nparm, parmlist, retype, ret)
  530. int current, nparm;
  531. struct pval *parmlist, *ret;
  532. {
  533.     int loop;
  534.  
  535.     printf("%s(",FUNCTIONS[current].name);
  536.     for (loop=0; loop<nparm; loop++) {
  537.         switch (parmlist->parmtype) {
  538.         case INTG:
  539.             printf("%d,",parmlist->v.u_int);
  540.             break;
  541.         case STRG:
  542.             printf("\"%s\",",parmlist->v.u_strg);
  543.             break;
  544.         }
  545.         parmlist++;
  546.     }
  547.     printf(")\n");
  548. }
  549. */
  550.  
  551. /* dummy function, to be compatible with MPrint */
  552. PrintPage()
  553. {
  554.     getch();   /* push any key to continue */
  555.     setgraph();
  556. }
  557.  
  558. int initvar(name,type)
  559. char *name;
  560. enum Ptype type;
  561. {
  562.     int varidx;
  563.  
  564.     if ((varidx=findvar(name)) == ERROR) {
  565.         printf("What happened! I can't find '%s'",name);
  566.         cleanup(1);
  567.     }
  568.     VARTABLE[varidx].parmtype=type;
  569.     return(varidx);
  570. }
  571.  
  572. initvars()
  573. {
  574.     int varidx;
  575.  
  576.     varidx=initvar("pattern1", STRG);
  577.     VARTABLE[varidx].v.u_strg=(char *) &PATTERN[0];
  578.     varidx=initvar("pattern2", STRG);
  579.     VARTABLE[varidx].v.u_strg=(char *) &PATTERN[16];
  580.     varidx=initvar("pattern3", STRG);
  581.     VARTABLE[varidx].v.u_strg=(char *) &PATTERN[32];
  582.     varidx=initvar("line", STRG);
  583.     VARTABLE[varidx].v.u_strg=LINE;
  584. }
  585.  
  586.