home *** CD-ROM | disk | FTP | other *** search
- /*
- ** This program demonstrates a parsing routine. It is based
- ** on a routine in "Advanced Turbo C" by Schildt, pub Borland,
- ** Osborne. It has been made more robust however.
- **
- ** This program now supports:
- **
- ** 1) arbitrary numbers of variables with a
- ** fortran-like naming convention (up to
- ** 30 characters) where the first symbol is
- ** a letter, and the rest are alphanumeric.
- ** These variables are created as they are
- ** referenced. They are all double's.
- **
- ** 2) The standard arithmetic functions: +, -, *, /,
- ** %, and ^. The ^ now supports double precision
- ** arguments and exponenets.
- **
- ** 3) An extended class of unary operators: +, -,
- ** sin, cos, tan, atan, ln, exp.
- **
- ** 4) A new class of delimiter (not arithmetic or
- ** unary, but called consts.) So far, the only
- ** constant supported is pi.
- **
- ** Added to Schildt's code was an extended lexical analyzer (function
- ** get_token() with supporting functions) which handles variable
- ** length variable names, variable length delimiters with alpha-numeric
- ** as well as symbolic forms, and more general numeric forms (it now
- ** supports numbers like -2.5e-43 and +.34e4, which would make Schilt's
- ** lexical analyzer die).
- **
- ** The strength of this code is that the
- ** lexical analyzer and subroutine structure is of a general enough
- ** form that the program could be more easily extended to doing
- ** supports of such syntaxes as `for', `while' and `if' statements.
- **
- ** It is now in a form which would be useful as a desk calculator,
- ** and which may be applied as the core of an interactive numerical
- ** analysis program (where graphs of solutions of differential
- ** equations may be obtained with interactively defined functions,
- ** for example).
- **
- ** Written by Dan Platt 12/12/1987
- **
- **/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <malloc.h>
- #include <ctype.h>
- #include <math.h>
-
- char *delim[] = {
-
- "=","+","-","*","/","%","^","(",")",
- "sin","cos","tan","atan","ln","exp","pi"
-
- };
-
- #define NDELIM 16
- #define NPROG 100
-
- char program[NPROG],
- *prog = program;
- token[NPROG],
- tok_type,
- delim_type;
-
- typedef struct variable {
- char name[30];
- double x;
- struct variable *next;
- } var;
-
- var *vars = NULL;
-
- #define DELIMITER 1
- #define VARIABLE 2
- #define NUMBER 3
-
- int isdelim()
- {
- int i,j,is_tok;
-
- for(i=0;i<NDELIM;i++){
-
- for(j=0,is_tok=1;(j<strlen(delim[i])) && is_tok; j++)
- is_tok = is_tok && (prog[j] == delim[i][j]);
-
- if(is_tok){
- delim_type=i;
- return 1;
- }
- }
- return 0;
- }
-
-
- int isdelim1(s)
- char *s;
- {
- int i,j,is_tok;
- static char *delim1[] = {
- "sin","cos","tan","atan","exp","ln","pi"
- };
-
- for(i=0;i<7;i++){
- is_tok=!strcmp(delim1[i],s);
- if(is_tok)return(1);
- }
- return(0);
-
- }
-
- void serror(s)
- int s;
- {
- static char *e[] = {
- "syntax error",
- "unbalanced parenthesis",
- "no expression present",
- "unrecognizable token: "
- };
- printf("%s\n",e[s]);
- exit(1);
- }
-
-
- void get_token()
- {
- char register *temp;
- int i;
- var *this,*last;
-
- tok_type=0;
- temp = (char *)token;
-
- while(*prog==' ')prog++;
-
- #define SIGN ((*prog == '+')||(*prog == '-'))
-
- if(isdigit(*prog)||(*prog == '.')){
-
- int go,
- dotflag,eflag,signflag;
-
- tok_type = NUMBER;
-
- dotflag = eflag = 0;
- signflag = 1;
- go = 1;
-
- while(go){
-
- if(isdigit(*prog)){
- *temp++ = *prog++;
- *temp='\0';
- signflag = 1;
- }
- else if(*prog == '.'){
- if(dotflag){
- fprintf(stderr,"syntax error - too many \'.\'s\n");
- exit(2);
- }
- signflag=1;
- dotflag=1;
- *temp++ = *prog++;
- *temp = '\0';
- } else if( SIGN && (!signflag)){
- if(isdigit(prog[1])||((prog[1]=='.') &&(!dotflag))){
- *temp++ = *prog++;
- *temp = '\0';
- signflag = 1;
- }
- else go=0;
- }
- else if((*prog == 'e')||(*prog == 'E')){
- if(!eflag){
- eflag = 1;
- signflag = 0;
- *temp++ = *prog++;
- *temp = '\0';
- } else {
- fprintf(stderr,"unexpected 'e' in number\n");
- exit(2);
- }
- }
- else go = 0;
- }
- temp = '\0';
- }
-
- #undef SIGN
-
- else
-
- if(isalpha(*prog)){
-
- char var_name[30], *tmpname, *oldprog;
-
- tmpname = (char *)var_name;
- oldprog = prog;
- while(isalpha(*prog)||isdigit(*prog))
- *tmpname++ = *prog++;
- *tmpname = '\0';
-
- if(!isdelim1((char*)var_name)){
- strcpy((char *)token,var_name);
- tok_type=VARIABLE;
-
- if(!vars){
-
- vars = (var *)malloc(sizeof(var));
- strcpy(vars -> name,(char *)token);
- vars -> next = NULL;
- vars -> x = 0;
-
- } else {
-
- for(this=vars,last=NULL;
- (this != NULL) &&
- strcmp(this -> name,(char *)token);
- this = (last=this) -> next);
- if(this == NULL){
- this = (var *)malloc(sizeof(var));
- last -> next = this;
- this -> next = NULL;
- strcpy(this ->name,(char *)token);
- this -> x = 0;
- }
- }
- }
- else {
- prog = oldprog;
- if(isdelim()){
- temp = (char *)token;
- tok_type = DELIMITER;
- for(i=0;i<strlen(delim[delim_type]);i++)
- *temp ++ = *prog ++;
- *temp = '\0';
- }
- }
- }
-
- else
-
- if(isdelim()){
- temp = (char *)token;
- tok_type = DELIMITER;
- for(i=0;i<strlen(delim[delim_type]);i++)
- *temp ++ = *prog ++;
- *temp = '\0';
- }
- }
-
- var *get_var(s)
- char *s;
- {
- var *this;
-
- for(this=vars;strcmp(this->name,s)&&this;this=this->next);
-
- return this;
- }
-
- double find_var(s)
- char *s;
- {
- var *this;
-
- if((this=get_var(s))!=NULL)return(this->x);
- serror(1);
- return(0.0);
- }
-
- void putback()
- {
- if(tok_type==DELIMITER)
- prog = &(prog[-strlen(delim[delim_type])]);
- else
- prog = &(prog[-strlen((char *)token)]);
- }
-
- int isunary(op)
- int op;
- {
- int i;
- int static uns[]={1,2,9,10,11,12,13,14};
-
- for(i=0;i<8;i++)if(uns[i]==op)return 1;
- return 0;
- }
-
- void primitive(result)
- double *result;
- {
-
- switch(tok_type){
-
- case VARIABLE:
- *result = find_var(token);
- get_token();
- return;
- case NUMBER:
- *result = atof((char *)token);
- get_token();
- return;
- default:
- serror(0);
- return;
- }
- }
-
- void arith(o,r,h)
- int o;
- double *r,*h;
- {
- int register t;
-
- switch(o){
- case 1:
- *r = *r + *h;
- break;
- case 2:
- *r = *r - *h;
- break;
- case 3:
- *r = (*r)*(*h);
- break;
- case 4:
- *r = (*r)/(*h);
- break;
- case 5:
- t = (*r)/(*h);
- *r = *r - t*(*h);
- break;
- case 6:
- *r = pow(*r,*h);
- break;
- }
- }
-
- void unary(o,r)
- int o;
- double *r;
- {
- switch(o){
-
- case 2:
- *r = -(*r);
- break;
- case 9:
- *r = sin(*r);
- break;
- case 10:
- *r = cos(*r);
- break;
- case 11:
- *r = tan(*r);
- break;
- case 12:
- *r = atan(*r);
- break;
- case 13:
- *r = log(*r);
- break;
- case 14:
- *r = exp(*r);
- break;
- }
- }
-
- void constnt(o,r)
- int o;
- double *r;
- {
- if(o==15)*r=3.1415926535897932384;
- }
-
- void level1(),
- level2(),
- level3(),
- level4(),
- level5(),
- level6();
-
- void level6(result)
- double *result;
- {
- if((tok_type==DELIMITER)&&(delim_type==7)){
- get_token();
- level1(result);
- if(delim_type!=8)serror(1);
- get_token();
- }
- else if((tok_type==DELIMITER)&&(delim_type==15)){
- constnt(delim_type,result);
- get_token();
- }
- else primitive(result);
- }
-
- void level5(result)
- double *result;
- {
- int op,isun;
-
- isun=0;
- if((tok_type==DELIMITER)&&((isun=isunary(delim_type))!=0)){
- op=delim_type;
- get_token();
- }
- level6(result);
- if(isun)unary(op,result);
- }
-
- void level4(result)
- double *result;
- {
- double hold;
-
- level5(result);
- if((tok_type==DELIMITER)&&(delim_type==6)){
- get_token();
- level5(&hold);
- arith(6,result,&hold);
- }
- }
-
- void level3(result)
- double *result;
- {
- register int op;
- double hold;
-
- level4(result);
- while((tok_type==DELIMITER)&&
- ((delim_type==3)||(delim_type==4)||(delim_type==5))){
- op=delim_type;
- get_token();
- level4(&hold);
- arith(op,result,&hold);
- }
- }
-
- void level2(result)
- double *result;
- {
- register int op;
- double hold;
-
- level3(result);
- while((tok_type==DELIMITER)&&
- ((delim_type==1)||(delim_type==2))){
- op=delim_type;
- get_token();
- level3(&hold);
- arith(op,result,&hold);
- }
- }
-
- void level1(result)
- double *result;
- {
- var *v;
- double hold;
- int ttok_type;
- char temp_token[NPROG];
-
- if(tok_type==VARIABLE){
-
- strcpy((char *)temp_token,(char *)token);
- ttok_type=tok_type;
- v = get_var(token);
- get_token();
-
- if((tok_type!=DELIMITER)||(delim_type!=0)){
- putback();
- strcpy((char *)token,(char *)temp_token);
- tok_type=ttok_type;
- } else {
- get_token();
- level2(result);
- v->x = *result;
- return;
- }
- }
- level2(result);
- }
-
- void get_exp(result)
- double *result;
- {
- get_token();
- if(!*token){
- serror(2);
- return;
- }
- level1(result);
- }
-
- main()
- {
- double answer;
-
- do{
- prog=program;
- printf("enter expression: ");
- gets(prog);
- if(!*prog)break;
- get_exp(&answer);
- printf("answer is: %24.18lg\n",answer);
- }while(1);
- }
-