This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
2017-03-18 23:04:38 +10:00

424 lines
6.8 KiB
C

#include <stdlib.h>
#include <string.h>
#include "shared/types.h"
#include "shared/expr.h"
#include <oslib/os.h>
#include <oslib/osmem.h>
struct expr *expr_get(struct expr *expr,int *errpos,char **errstr)
{
int c,d,len,start;
bool hasnot,hasquote,stop;
struct expr *res;
hasnot=FALSE;
c=expr->parsepos;
/* Skip leading whitespace */
while(expr->buf[c]==' ')
c++;
/* Check for NOT */
if(strnicmp(&expr->buf[c],"NOT ",4)==0)
{
c+=4;
hasnot=TRUE;
}
/* Check if parentheses */
if(expr->buf[c]=='(')
{
int nump;
nump=1;
d=c+1;
while(nump!=0 && expr->buf[d]!=0)
{
if(expr->buf[d]=='(') nump++;
if(expr->buf[d]==')') nump--;
d++;
}
if(nump == 0)
{
start=c+1;
len=d-c-2;
if(!(res=osAlloc(sizeof(struct expr))))
{
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
if(!(res->buf=osAlloc(len+10)))
{
osFree(res);
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
res->parsepos=0;
res->offset=expr->offset+start;
res->buf[0]=0;
if(hasnot)
strcat(res->buf,"NOT ");
strncat(res->buf,&expr->buf[start],len);
expr->parsepos=d;
return(res);
}
else
{
*errpos=expr->offset+c;
*errstr="No matching parenthesis found";
return(NULL);
}
}
d=c;
stop=FALSE;
hasquote=FALSE;
while(!stop)
{
if(expr->buf[d] == 0)
stop=TRUE;
if(expr->buf[d] == ' ' && !hasquote)
stop=TRUE;
if(expr->buf[d] == '"' && hasquote)
stop=TRUE;
if(expr->buf[d] == '"')
hasquote=TRUE;
if(!stop)
d++;
}
if(expr->buf[d]=='"')
d++;
start=c;
len=d-c;
if(!(res=osAlloc(sizeof(struct expr))))
{
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
if(!(res->buf=osAlloc(len+10)))
{
osFree(res);
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
res->parsepos=0;
res->offset=expr->offset+start;
res->buf[0]=0;
if(hasnot)
strcat(res->buf,"NOT ");
strncat(res->buf,&expr->buf[start],len);
expr->parsepos=d;
return(res);
}
struct expr *expr_getrest(struct expr *expr,int *errpos,char **errstr)
{
int c,d,start,len;
struct expr *res;
c=expr->parsepos;
/* Skip leading whitespace */
while(expr->buf[c]==' ')
c++;
d=c;
while(expr->buf[d]!=0)
d++;
start=c;
len=d-c;
if(!(res=osAlloc(sizeof(struct expr))))
{
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
if(!(res->buf=osAlloc(len+10)))
{
osFree(res);
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
res->parsepos=0;
res->offset=expr->offset+start;
res->buf[0]=0;
strncat(res->buf,&expr->buf[start],len);
expr->parsepos=d;
return(res);
}
struct expr *expr_makeexpr(char *str)
{
struct expr *expr;
if(!(expr=osAllocCleared(sizeof(struct expr))))
{
return(NULL);
}
if(!(expr->buf=osAlloc(strlen(str)+1)))
{
osFree(expr);
return(NULL);
}
strcpy(expr->buf,str);
return(expr);
}
void expr_free(struct expr *expr)
{
osFree(expr->buf);
osFree(expr);
}
int expr_eval(struct expr *expr,int (*eval)(char *str,int *errpos,char **errstr),int *errpos,char **errstr)
{
struct expr *e1,*e2,*e3;
e1=expr_get(expr,errpos,errstr);
if(!e1)
{
return(-1);
}
e2=expr_get(expr,errpos,errstr);
if(!e2)
{
expr_free(e1);
return(-1);
}
e3=expr_getrest(expr,errpos,errstr);
if(!e3)
{
expr_free(e1);
expr_free(e2);
return(-1);
}
if(e2->buf[0] == 0)
{
/* Only one expression */
if(strcmp(e1->buf,expr->buf)==0)
{
/* No more simplification possible */
if(strnicmp(e1->buf,"NOT ",4)==0)
{
int res;
strcpy(e1->buf,&e1->buf[4]);
e1->parsepos=0;
res=expr_eval(e1,eval,errpos,errstr);
if(res == 1) res=0;
else if(res == 0) res=1;
/* printf("NOT |%s|: %d\n",e1->buf,res); */
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(res);
}
else
{
int res,tmperrpos;
res=(*eval)(e1->buf,&tmperrpos,errstr);
if(res == -1)
*errpos=e1->offset+tmperrpos;
/* printf("EVAL: |%s|: %d\n",e1->buf,res); */
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(res);
}
}
else
{
int res;
res=expr_eval(e1,eval,errpos,errstr);
/* printf("|%s|: %d\n",e1->buf,res); */
expr_free(e1);
expr_free(e2);
expr_free(e3);
return (res);
}
}
if(stricmp(e2->buf,"AND")==0)
{
int r1,r2,res;
if(e3->buf[0] == 0)
{
*errstr="Expected second expression after AND";
*errpos=e3->offset;
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
r1=expr_eval(e1,eval,errpos,errstr);
if(r1 == -1)
{
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
r2=expr_eval(e3,eval,errpos,errstr);
if(r2 == -1)
{
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
res=0;
if(r1 && r2)
res=1;
/* printf("|%s| AND |%s|: %d\n",e1->buf,e3->buf,res); */
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(res);
}
else if(stricmp(e2->buf,"OR")==0)
{
int r1,r2,res;
if(e3->buf[0] == 0)
{
*errstr="Expected second expression after OR";
*errpos=e3->offset;
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
r1=expr_eval(e1,eval,errpos,errstr);
if(r1 == -1)
{
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
r2=expr_eval(e3,eval,errpos,errstr);
if(r2 == -1)
{
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
res=0;
if(r1 || r2)
res=1;
/* printf("|%s| OR |%s|: %d\n",e1->buf,e3->buf,res); */
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(res);
}
else
{
*errstr="Expected AND or OR";
*errpos=e2->offset;
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
}