home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / tools / exe2bin / exe2com / parse.c < prev    next >
C/C++ Source or Header  |  1987-12-11  |  10KB  |  517 lines

  1. /*
  2. **      This program demonstrates a parsing routine.  It is based
  3. **      on a routine in "Advanced Turbo C" by Schildt, pub Borland,
  4. **      Osborne.  It has been made more robust however.
  5. **
  6. **      This program now supports:
  7. **
  8. **              1)      arbitrary numbers of variables with a
  9. **                      fortran-like naming convention (up to
  10. **                      30 characters) where the first symbol is
  11. **                      a letter, and the rest are alphanumeric.
  12. **                      These variables are created as they are
  13. **                      referenced.  They are all double's.
  14. **
  15. **              2)      The standard arithmetic functions: +, -, *, /,
  16. **                      %, and ^.  The ^ now supports double precision
  17. **                      arguments and exponenets.
  18. **
  19. **              3)      An extended class of unary operators: +, -,
  20. **                      sin, cos, tan, atan, ln, exp.
  21. **
  22. **              4)      A new class of delimiter (not arithmetic or
  23. **                      unary, but called consts.)  So far, the only
  24. **                      constant supported is pi.
  25. **
  26. **      Added to Schildt's code was an extended lexical analyzer (function
  27. **      get_token() with supporting functions) which handles variable
  28. **      length variable names, variable length delimiters with alpha-numeric
  29. **      as well as symbolic forms, and more general numeric forms (it now
  30. **      supports numbers like -2.5e-43 and +.34e4, which would make Schilt's
  31. **      lexical analyzer die).
  32. **
  33. **      The strength of this code is that the
  34. **      lexical analyzer and subroutine structure is of a general enough
  35. **      form that the program could be more easily extended to doing
  36. **      supports of such syntaxes as `for', `while' and `if' statements.
  37. **
  38. **      It is now in a form which would be useful as a desk calculator,
  39. **      and which may be applied as the core of an interactive numerical
  40. **      analysis program (where graphs of solutions of differential
  41. **      equations may be obtained with interactively defined functions,
  42. **      for example).
  43. **
  44. **      Written by Dan Platt    12/12/1987
  45. **
  46. **/
  47.  
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include <malloc.h>
  52. #include <ctype.h>
  53. #include <math.h>
  54.  
  55. char    *delim[] = {
  56.  
  57.         "=","+","-","*","/","%","^","(",")",
  58.         "sin","cos","tan","atan","ln","exp","pi"
  59.  
  60.     };
  61.  
  62. #define NDELIM    16
  63. #define NPROG    100
  64.  
  65. char    program[NPROG],
  66.     *prog = program;
  67.     token[NPROG],
  68.     tok_type,
  69.     delim_type;
  70.  
  71. typedef struct variable {
  72.     char name[30];
  73.     double x;
  74.     struct variable *next;
  75.     } var;
  76.  
  77. var *vars = NULL;
  78.  
  79. #define DELIMITER    1
  80. #define VARIABLE    2
  81. #define NUMBER        3
  82.  
  83. int isdelim()
  84. {
  85.     int i,j,is_tok;
  86.  
  87.     for(i=0;i<NDELIM;i++){
  88.  
  89.         for(j=0,is_tok=1;(j<strlen(delim[i])) && is_tok; j++)
  90.             is_tok = is_tok && (prog[j] == delim[i][j]);
  91.  
  92.         if(is_tok){
  93.             delim_type=i;
  94.             return 1;
  95.         }
  96.     }
  97.     return 0;
  98. }
  99.  
  100.  
  101. int isdelim1(s)
  102. char *s;
  103. {
  104.     int i,j,is_tok;
  105.     static char *delim1[] = {
  106.         "sin","cos","tan","atan","exp","ln","pi"
  107.         };
  108.  
  109.     for(i=0;i<7;i++){
  110.         is_tok=!strcmp(delim1[i],s);
  111.         if(is_tok)return(1);
  112.     }
  113.     return(0);
  114.  
  115. }
  116.  
  117. void serror(s)
  118. int s;
  119. {
  120.     static char *e[] = {
  121.         "syntax error",
  122.         "unbalanced parenthesis",
  123.         "no expression present",
  124.         "unrecognizable token: "
  125.     };
  126.     printf("%s\n",e[s]);
  127.     exit(1);
  128. }
  129.  
  130.  
  131. void get_token()
  132. {
  133.     char register *temp;
  134.     int i;
  135.     var *this,*last;
  136.  
  137.     tok_type=0;
  138.     temp = (char *)token;
  139.  
  140.     while(*prog==' ')prog++;
  141.  
  142. #define SIGN ((*prog == '+')||(*prog == '-'))
  143.  
  144.     if(isdigit(*prog)||(*prog == '.')){
  145.  
  146.         int     go,
  147.             dotflag,eflag,signflag;
  148.  
  149.         tok_type = NUMBER;
  150.  
  151.         dotflag = eflag = 0;
  152.         signflag = 1;
  153.         go = 1;
  154.  
  155.         while(go){
  156.  
  157.             if(isdigit(*prog)){
  158.                 *temp++ = *prog++;
  159.                 *temp='\0';
  160.                 signflag = 1;
  161.             }
  162.             else if(*prog == '.'){
  163.                 if(dotflag){
  164.                     fprintf(stderr,"syntax error - too many \'.\'s\n");
  165.                     exit(2);
  166.                 }
  167.                 signflag=1;
  168.                 dotflag=1;
  169.                 *temp++ = *prog++;
  170.                 *temp = '\0';
  171.             } else if( SIGN && (!signflag)){
  172.                 if(isdigit(prog[1])||((prog[1]=='.') &&(!dotflag))){
  173.                     *temp++ = *prog++;
  174.                     *temp = '\0';
  175.                     signflag = 1;
  176.                 }
  177.                 else go=0;
  178.             }
  179.             else if((*prog == 'e')||(*prog == 'E')){
  180.                 if(!eflag){
  181.                     eflag = 1;
  182.                     signflag = 0;
  183.                     *temp++ = *prog++;
  184.                     *temp = '\0';
  185.                 } else {
  186.                     fprintf(stderr,"unexpected 'e' in number\n");
  187.                     exit(2);
  188.                 }
  189.             }
  190.             else go = 0;
  191.         }
  192.         temp = '\0';
  193.     }
  194.  
  195. #undef SIGN
  196.  
  197.     else
  198.  
  199.     if(isalpha(*prog)){
  200.  
  201.         char var_name[30], *tmpname, *oldprog;
  202.  
  203.         tmpname = (char *)var_name;
  204.         oldprog = prog;
  205.         while(isalpha(*prog)||isdigit(*prog))
  206.             *tmpname++ = *prog++;
  207.         *tmpname = '\0';
  208.  
  209.         if(!isdelim1((char*)var_name)){
  210.             strcpy((char *)token,var_name);
  211.             tok_type=VARIABLE;
  212.  
  213.             if(!vars){
  214.  
  215.                 vars = (var *)malloc(sizeof(var));
  216.                 strcpy(vars -> name,(char *)token);
  217.                 vars -> next = NULL;
  218.                 vars -> x = 0;
  219.  
  220.             } else {
  221.  
  222.                 for(this=vars,last=NULL;
  223.                     (this != NULL) &&
  224.                     strcmp(this -> name,(char *)token);
  225.                     this = (last=this) -> next);
  226.                 if(this == NULL){
  227.                     this = (var *)malloc(sizeof(var));
  228.                     last -> next = this;
  229.                     this -> next = NULL;
  230.                     strcpy(this ->name,(char *)token);
  231.                     this -> x = 0;
  232.                 }
  233.             }
  234.         }
  235.         else {
  236.             prog = oldprog;
  237.             if(isdelim()){
  238.                 temp = (char *)token;
  239.                 tok_type = DELIMITER;
  240.                 for(i=0;i<strlen(delim[delim_type]);i++)
  241.                     *temp ++ = *prog ++;
  242.                 *temp = '\0';
  243.             }
  244.         }
  245.     }
  246.  
  247.     else
  248.  
  249.     if(isdelim()){
  250.         temp = (char *)token;
  251.         tok_type = DELIMITER;
  252.         for(i=0;i<strlen(delim[delim_type]);i++)
  253.             *temp ++ = *prog ++;
  254.         *temp = '\0';
  255.     }
  256. }
  257.  
  258. var *get_var(s)
  259. char *s;
  260. {
  261.     var *this;
  262.  
  263.     for(this=vars;strcmp(this->name,s)&&this;this=this->next);
  264.  
  265.     return this;
  266. }
  267.  
  268. double find_var(s)
  269. char *s;
  270. {
  271.     var *this;
  272.  
  273.     if((this=get_var(s))!=NULL)return(this->x);
  274.     serror(1);
  275.     return(0.0);
  276. }
  277.  
  278. void putback()
  279. {
  280.     if(tok_type==DELIMITER)
  281.         prog = &(prog[-strlen(delim[delim_type])]);
  282.     else    
  283.         prog = &(prog[-strlen((char *)token)]);
  284. }
  285.  
  286. int isunary(op)
  287. int op;
  288. {
  289.     int    i;
  290.     int static uns[]={1,2,9,10,11,12,13,14};
  291.  
  292.     for(i=0;i<8;i++)if(uns[i]==op)return 1;
  293.     return 0;
  294. }
  295.  
  296. void primitive(result)
  297. double *result;
  298. {
  299.  
  300.     switch(tok_type){
  301.  
  302.         case VARIABLE:
  303.             *result = find_var(token);
  304.             get_token();
  305.             return;
  306.         case NUMBER:
  307.             *result = atof((char *)token);
  308.             get_token();
  309.             return;
  310.         default:
  311.             serror(0);
  312.             return;
  313.     }
  314. }
  315.  
  316. void arith(o,r,h)
  317. int o;
  318. double *r,*h;
  319. {
  320.     int register t;
  321.  
  322.     switch(o){
  323.         case 1:
  324.             *r = *r + *h;
  325.             break;
  326.         case 2:
  327.             *r = *r - *h;
  328.             break;
  329.         case 3:
  330.             *r = (*r)*(*h);
  331.             break;
  332.         case 4:
  333.             *r = (*r)/(*h);
  334.             break;
  335.         case 5:
  336.             t = (*r)/(*h);
  337.             *r = *r - t*(*h);
  338.             break;
  339.         case 6:
  340.             *r = pow(*r,*h);
  341.             break;
  342.     }
  343. }
  344.  
  345. void unary(o,r)
  346. int o;
  347. double *r;
  348. {
  349.     switch(o){
  350.  
  351.         case 2:
  352.             *r = -(*r);
  353.             break;
  354.         case 9:
  355.             *r = sin(*r);
  356.             break;
  357.         case 10:
  358.             *r = cos(*r);
  359.             break;
  360.         case 11:
  361.             *r = tan(*r);
  362.             break;
  363.         case 12:
  364.             *r = atan(*r);
  365.             break;
  366.         case 13:
  367.             *r = log(*r);
  368.             break;
  369.         case 14:
  370.             *r = exp(*r);
  371.             break;
  372.     }
  373. }
  374.  
  375. void constnt(o,r)
  376. int o;
  377. double *r;
  378. {
  379.     if(o==15)*r=3.1415926535897932384;
  380. }
  381.  
  382. void    level1(),
  383.     level2(),
  384.     level3(),
  385.     level4(),
  386.     level5(),
  387.     level6();
  388.  
  389. void level6(result)
  390. double *result;
  391. {
  392.     if((tok_type==DELIMITER)&&(delim_type==7)){
  393.         get_token();
  394.         level1(result);
  395.         if(delim_type!=8)serror(1);
  396.         get_token();
  397.     }
  398.     else if((tok_type==DELIMITER)&&(delim_type==15)){
  399.         constnt(delim_type,result);
  400.         get_token();
  401.     }
  402.     else primitive(result);
  403. }
  404.  
  405. void level5(result)
  406. double *result;
  407. {
  408.     int op,isun;
  409.  
  410.     isun=0;
  411.     if((tok_type==DELIMITER)&&((isun=isunary(delim_type))!=0)){
  412.         op=delim_type;
  413.         get_token();
  414.     }
  415.     level6(result);
  416.     if(isun)unary(op,result);
  417. }
  418.  
  419. void level4(result)
  420. double *result;
  421. {
  422.     double hold;
  423.  
  424.     level5(result);
  425.     if((tok_type==DELIMITER)&&(delim_type==6)){
  426.         get_token();
  427.         level5(&hold);
  428.         arith(6,result,&hold);
  429.     }
  430. }
  431.  
  432. void level3(result)
  433. double *result;
  434. {
  435.     register int op;
  436.     double hold;
  437.  
  438.     level4(result);
  439.     while((tok_type==DELIMITER)&&
  440.         ((delim_type==3)||(delim_type==4)||(delim_type==5))){
  441.             op=delim_type;
  442.             get_token();
  443.             level4(&hold);
  444.             arith(op,result,&hold);
  445.     }
  446. }
  447.  
  448. void level2(result)
  449. double *result;
  450. {
  451.     register int op;
  452.     double hold;
  453.  
  454.     level3(result);
  455.     while((tok_type==DELIMITER)&&
  456.         ((delim_type==1)||(delim_type==2))){
  457.             op=delim_type;
  458.             get_token();
  459.             level3(&hold);
  460.             arith(op,result,&hold);
  461.     }
  462. }
  463.  
  464. void level1(result)
  465. double *result;
  466. {
  467.     var *v;
  468.     double hold;
  469.     int ttok_type;
  470.     char temp_token[NPROG];
  471.  
  472.     if(tok_type==VARIABLE){
  473.  
  474.         strcpy((char *)temp_token,(char *)token);
  475.         ttok_type=tok_type;
  476.         v = get_var(token);
  477.         get_token();
  478.  
  479.         if((tok_type!=DELIMITER)||(delim_type!=0)){
  480.             putback();
  481.             strcpy((char *)token,(char *)temp_token);
  482.             tok_type=ttok_type;
  483.         } else {
  484.             get_token();
  485.             level2(result);
  486.             v->x = *result;
  487.             return;
  488.         }
  489.     }
  490.     level2(result);
  491. }
  492.  
  493. void get_exp(result)
  494. double *result;
  495. {
  496.     get_token();
  497.     if(!*token){
  498.         serror(2);
  499.         return;
  500.     }
  501.     level1(result);
  502. }
  503.  
  504. main()
  505. {
  506.     double answer;
  507.  
  508.     do{
  509.         prog=program;
  510.         printf("enter expression: ");
  511.         gets(prog);
  512.         if(!*prog)break;
  513.         get_exp(&answer);
  514.         printf("answer is: %24.18lg\n",answer);
  515.     }while(1);
  516. }
  517.