parse tree completely built, int and string values appear to be working

This commit is contained in:
Ron Pedde 2005-10-20 07:33:58 +00:00
parent 939db9fcf9
commit b32984abeb

View File

@ -31,6 +31,7 @@ typedef struct tag_sp_node {
} left; } left;
int op; int op;
int op_type;
union { union {
struct tag_sp_node *node; struct tag_sp_node *node;
@ -39,6 +40,12 @@ typedef struct tag_sp_node {
} right; } right;
} SP_NODE; } SP_NODE;
#define SP_OPTYPE_ANDOR 0
#define SP_OPTYPE_STRING 1
#define SP_OPTYPE_INT 2
#define SP_OPTYPE_DATE 3
/* /*
#define T_ID 0x00 #define T_ID 0x00
#define T_PATH 0x01 #define T_PATH 0x01
@ -182,17 +189,36 @@ typedef struct tag_parsetree {
char *current; char *current;
SP_TOKEN token; SP_TOKEN token;
SP_TOKEN next_token; SP_TOKEN next_token;
SP_NODE *tree;
} PARSESTRUCT, *PARSETREE; } PARSESTRUCT, *PARSETREE;
/* Forwards */ /* Forwards */
int sp_parse_phrase(PARSETREE tree); SP_NODE *sp_parse_phrase(PARSETREE tree);
int sp_parse_aexpr(PARSETREE tree); SP_NODE *sp_parse_aexpr(PARSETREE tree);
int sp_parse_oexpr(PARSETREE tree); SP_NODE *sp_parse_oexpr(PARSETREE tree);
int sp_parse_expr(PARSETREE tree); SP_NODE *sp_parse_expr(PARSETREE tree);
int sp_parse_criterion(PARSETREE tree); SP_NODE *sp_parse_criterion(PARSETREE tree);
int sp_parse_string_criterion(PARSETREE tree); SP_NODE *sp_parse_string_criterion(PARSETREE tree);
int sp_parse_int_criterion(PARSETREE tree); SP_NODE *sp_parse_int_criterion(PARSETREE tree);
int sp_parse_date_criterion(PARSETREE tree); SP_NODE *sp_parse_date_criterion(PARSETREE tree);
void sp_free_node(SP_NODE *);
/**
* see if a string is actually a number
*
* @param string string to check
* @returns 1 if the string is numeric, 0 otherwise
*/
int sp_isnumber(char *string) {
char *current=string;
while(*current && (*current >= '0') && (*current <= '9')) {
current++;
}
return *current ? 0 : 1;
}
/** /**
* scan the input, returning the next available token. * scan the input, returning the next available token.
@ -208,6 +234,7 @@ int sp_scan(PARSETREE tree) {
FIELDLOOKUP *pfield=sp_fields; FIELDLOOKUP *pfield=sp_fields;
int len; int len;
int found; int found;
int numval;
if(tree->token.token_id & 0x2000) { if(tree->token.token_id & 0x2000) {
if(tree->token.data.cvalue) if(tree->token.data.cvalue)
@ -344,6 +371,14 @@ int sp_scan(PARSETREE tree) {
} }
/* check for numberic? */ /* check for numberic? */
if(tree->next_token.token_id == T_STRING &&
sp_isnumber(tree->next_token.data.cvalue)) {
/* woops! */
numval = atoi(tree->next_token.data.cvalue);
free(tree->next_token.data.cvalue);
tree->next_token.data.ivalue = numval;
tree->next_token.token_id = T_NUMBER;
}
tree->current=tail; tree->current=tail;
} }
@ -402,13 +437,18 @@ int sp_parse(PARSETREE tree, char *term) {
sp_scan(tree); sp_scan(tree);
sp_scan(tree); sp_scan(tree);
if(sp_parse_phrase(tree)) { if(tree->tree)
sp_free_node(tree->tree);
tree->tree = sp_parse_phrase(tree);
if(tree->tree) {
DPRINTF(E_SPAM,L_PARSE,"Parsed successfully\n"); DPRINTF(E_SPAM,L_PARSE,"Parsed successfully\n");
} else { } else {
DPRINTF(E_SPAM,L_PARSE,"Parsing error\n"); DPRINTF(E_SPAM,L_PARSE,"Parsing error\n");
} }
return 1; return tree->tree ? 1 : 0;
} }
@ -418,21 +458,24 @@ int sp_parse(PARSETREE tree, char *term) {
* phrase -> aexpr T_EOF * phrase -> aexpr T_EOF
* *
* @param tree tree we are parsing (and building) * @param tree tree we are parsing (and building)
* @returns 1 if successful, 0 otherwise * @returns new SP_NODE * if successful, NULL otherwise
*/ */
int sp_parse_phrase(PARSETREE tree) { SP_NODE *sp_parse_phrase(PARSETREE tree) {
int result=0; SP_NODE *expr;
DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_phrase\n"); DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_phrase\n");
if(sp_parse_aexpr(tree) && (tree->token.token_id == T_EOF)) expr = sp_parse_aexpr(tree);
result=1; if((!expr) || (tree->token.token_id != T_EOF)) {
sp_free_node(expr);
expr = NULL;
}
DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_phrase: %s\n",result ? DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_phrase: %s\n",expr ?
"success" : "fail"); "success" : "fail");
return result; return expr;
} }
/** /**
@ -441,22 +484,42 @@ int sp_parse_phrase(PARSETREE tree) {
* aexpr -> oexpr { T_AND oexpr } * aexpr -> oexpr { T_AND oexpr }
* *
* @param tree tree we are building * @param tree tree we are building
* @returns 1 if successful, 0 otherwise * @returns new SP_NODE pointer if successful, NULL otherwise
*/ */
int sp_parse_aexpr(PARSETREE tree) { SP_NODE *sp_parse_aexpr(PARSETREE tree) {
int result=0; SP_NODE *expr;
SP_NODE *pnew;
DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_aexpr\n"); DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_aexpr\n");
while(1) { expr = sp_parse_expr(tree);
result = sp_parse_oexpr(tree);
if((!result) || (tree->token.token_id != T_AND)) break; while(expr && (tree->token.token_id == T_AND)) {
pnew = (SP_NODE*)malloc(sizeof(SP_NODE));
if(!pnew) {
DPRINTF(E_FATAL,L_PARSE,"Malloc error\n");
}
memset(pnew,0x00,sizeof(SP_NODE));
pnew->op=T_AND;
pnew->op_type = SP_OPTYPE_ANDOR;
pnew->left.node = expr;
sp_scan(tree);
pnew->right.node = sp_parse_expr(tree);
if(!pnew->right.node) {
sp_free_node(pnew);
pnew=NULL;
}
expr=pnew;
} }
DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_aexpr: %s\n",result ? DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_aexpr: %s\n",expr ?
"success" : "fail"); "success" : "fail");
return result; return expr;
} }
/** /**
@ -465,22 +528,42 @@ int sp_parse_aexpr(PARSETREE tree) {
* oexpr -> expr { T_OR expr } * oexpr -> expr { T_OR expr }
* *
* @param tree tree we are building * @param tree tree we are building
* @returns 1 if successful, 0 otherwise * @returns new SP_NODE pointer if successful, NULL otherwise
*/ */
int sp_parse_oexpr(PARSETREE tree) { SP_NODE *sp_parse_oexpr(PARSETREE tree) {
int result=0; SP_NODE *expr;
SP_NODE *pnew;
DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_oexpr\n"); DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_oexpr\n");
while(1) { expr = sp_parse_expr(tree);
result = sp_parse_expr(tree);
if((!result) || (tree->token.token_id != T_OR)) break; while(expr && (tree->token.token_id == T_OR)) {
pnew = (SP_NODE*)malloc(sizeof(SP_NODE));
if(!pnew) {
DPRINTF(E_FATAL,L_PARSE,"Malloc error\n");
}
memset(pnew,0x00,sizeof(SP_NODE));
pnew->op=T_OR;
pnew->op_type = SP_OPTYPE_ANDOR;
pnew->left.node = expr;
sp_scan(tree);
pnew->right.node = sp_parse_expr(tree);
if(!pnew->right.node) {
sp_free_node(pnew);
pnew=NULL;
}
expr=pnew;
} }
DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_oexpr: %s\n",result ? DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_oexpr: %s\n",expr ?
"success" : "fail"); "success" : "fail");
return result; return expr;
} }
/** /**
@ -489,29 +572,30 @@ int sp_parse_oexpr(PARSETREE tree) {
* expr -> T_OPENPAREN aexpr T_CLOSEPAREN | criteria * expr -> T_OPENPAREN aexpr T_CLOSEPAREN | criteria
* *
* @param tree tree we are building * @param tree tree we are building
* @returns 1 if successful, 0 otherwise * @returns pointer to new SP_NODE if successful, NULL otherwise
*/ */
int sp_parse_expr(PARSETREE tree) { SP_NODE *sp_parse_expr(PARSETREE tree) {
int result=0; SP_NODE *expr;
DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_expr\n"); DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_expr\n");
if(tree->token.token_id == T_OPENPAREN) { if(tree->token.token_id == T_OPENPAREN) {
sp_scan(tree); sp_scan(tree);
result = sp_parse_aexpr(tree); expr = sp_parse_aexpr(tree);
if((result) && (tree->token.token_id == T_OPENPAREN)) { if((expr) && (tree->token.token_id == T_CLOSEPAREN)) {
sp_scan(tree); sp_scan(tree);
} else { } else {
/* Error: expecting close paren */ /* Error: expecting close paren */
result=0; sp_free_node(expr);
expr=NULL;
} }
} else { } else {
result = sp_parse_criterion(tree); expr = sp_parse_criterion(tree);
} }
DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_expr: %s\n",result ? DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_expr: %s\n",expr ?
"success" : "fail"); "success" : "fail");
return result; return expr;
} }
/** /**
@ -520,53 +604,63 @@ int sp_parse_expr(PARSETREE tree) {
* criterion -> field op value * criterion -> field op value
* *
* @param tree tree we are building * @param tree tree we are building
* @returns 1 if successful, 0 otherwise * @returns pointer to new SP_NODE if successful, NULL otherwise.
*/ */
int sp_parse_criterion(PARSETREE tree) { SP_NODE *sp_parse_criterion(PARSETREE tree) {
int result=0; SP_NODE *expr=NULL;
DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_criterion\n"); DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_criterion\n");
switch(tree->token.token_id) { switch(tree->token.token_id) {
case T_STRING_FIELD: case T_STRING_FIELD:
result = sp_parse_string_criterion(tree); expr = sp_parse_string_criterion(tree);
break; break;
case T_INT_FIELD: case T_INT_FIELD:
result = sp_parse_int_criterion(tree); expr = sp_parse_int_criterion(tree);
break; break;
case T_DATE_FIELD: case T_DATE_FIELD:
result = sp_parse_date_criterion(tree); expr = sp_parse_date_criterion(tree);
break; break;
default: default:
/* Error: expecting field */ /* Error: expecting field */
result = 0; expr = NULL;
break; break;
} }
DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_criterion: %s\n",result ? DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_criterion: %s\n",expr ?
"success" : "fail"); "success" : "fail");
return result; return expr;
} }
/** /**
* parse for a string criterion * parse for a string criterion
* *
* @param tree tree we are building * @param tree tree we are building
* @returns 1 if successful, 0 otherwise * @returns pointer to new SP_NODE if successful, NULL otherwise
*/ */
int sp_parse_string_criterion(PARSETREE tree) { SP_NODE *sp_parse_string_criterion(PARSETREE tree) {
int result=0; int result=0;
SP_NODE *pnew = NULL;
DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_string_criterion\n"); DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_string_criterion\n");
pnew = malloc(sizeof(SP_NODE));
if(!pnew) {
DPRINTF(E_FATAL,L_PARSE,"Malloc Error\n");
}
memset(pnew,0x00,sizeof(SP_NODE));
pnew->left.field = strdup(tree->token.data.cvalue);
sp_scan(tree); /* scan past the string field we know is there */ sp_scan(tree); /* scan past the string field we know is there */
switch(tree->token.token_id) { switch(tree->token.token_id) {
case T_EQUAL: case T_EQUAL:
pnew->op=tree->token.token_id;
pnew->op_type = SP_OPTYPE_STRING;
result = 1; result = 1;
break; break;
default: default:
@ -581,6 +675,7 @@ int sp_parse_criterion(PARSETREE tree) {
if(tree->token.token_id == T_QUOTE) { if(tree->token.token_id == T_QUOTE) {
sp_scan(tree); sp_scan(tree);
if(tree->token.token_id == T_STRING) { if(tree->token.token_id == T_STRING) {
pnew->right.cvalue=strdup(tree->token.data.cvalue);
sp_scan(tree); sp_scan(tree);
if(tree->token.token_id == T_QUOTE) { if(tree->token.token_id == T_QUOTE) {
result=1; result=1;
@ -596,22 +691,35 @@ int sp_parse_criterion(PARSETREE tree) {
} }
} }
if(!result) {
sp_free_node(pnew);
pnew=NULL;
}
DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_string_criterion: %s\n",result ? DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_string_criterion: %s\n",result ?
"success" : "fail"); "success" : "fail");
return result; return pnew;
} }
/** /**
* parse for an int criterion * parse for an int criterion
* *
* @param tree tree we are building * @param tree tree we are building
* @returns 1 if successful, 0 otherwise * @returns address of new SP_NODE if successful, NULL otherwise
*/ */
int sp_parse_int_criterion(PARSETREE tree) { SP_NODE *sp_parse_int_criterion(PARSETREE tree) {
int result=0; int result=0;
SP_NODE *pnew = NULL;
DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_int_criterion\n"); DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_int_criterion\n");
pnew = malloc(sizeof(SP_NODE));
if(!pnew) {
DPRINTF(E_FATAL,L_PARSE,"Malloc Error\n");
}
memset(pnew,0x00,sizeof(SP_NODE));
pnew->left.field = strdup(tree->token.data.cvalue);
sp_scan(tree); /* scan past the int field we know is there */ sp_scan(tree); /* scan past the int field we know is there */
@ -622,6 +730,8 @@ int sp_parse_criterion(PARSETREE tree) {
case T_GREATER: case T_GREATER:
case T_EQUAL: case T_EQUAL:
result = 1; result = 1;
pnew->op=tree->token.token_id;
pnew->op_type = SP_OPTYPE_INT;
break; break;
default: default:
/* Error: expecting legal string comparison operator */ /* Error: expecting legal string comparison operator */
@ -635,20 +745,25 @@ int sp_parse_criterion(PARSETREE tree) {
/* should be sitting on a literal string */ /* should be sitting on a literal string */
if(tree->token.token_id == T_NUMBER) { if(tree->token.token_id == T_NUMBER) {
result = 1; result = 1;
pnew->right.ivalue=tree->token.data.ivalue;
sp_scan(tree); sp_scan(tree);
} else { } else {
/* Error: Expecting literal string */ /* Error: Expecting number */
DPRINTF(E_LOG,L_PARSE,"Expecting string literal, got %04X\n", DPRINTF(E_LOG,L_PARSE,"Expecting number, got %04X\n",
tree->token.token_id); tree->token.token_id);
result = 0; result = 0;
} }
} }
if(!result) {
sp_free_node(pnew);
pnew=NULL;
}
DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_int_criterion: %s\n",result ? DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_int_criterion: %s\n",result ?
"success" : "fail"); "success" : "fail");
return result; return pnew;
} }
@ -656,19 +771,57 @@ int sp_parse_criterion(PARSETREE tree) {
* parse for a date criterion * parse for a date criterion
* *
* @param tree tree we are building * @param tree tree we are building
* @returns 1 if successful, 0 otherwise * @returns pointer to new SP_NODE if successful, NULL otherwise
*/ */
int sp_parse_date_criterion(PARSETREE tree) { SP_NODE *sp_parse_date_criterion(PARSETREE tree) {
int result=0; int result=0;
SP_NODE *pnew=NULL;
DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_date_criterion\n"); DPRINTF(E_SPAM,L_PARSE,"Entering sp_parse_date_criterion\n");
DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_date_criterion: %s\n",result ? DPRINTF(E_SPAM,L_PARSE,"Exiting sp_parse_date_criterion: %s\n",result ?
"success" : "fail"); "success" : "fail");
return result; return pnew;
} }
/**
* free a node, and all left/right subnodes
*
* @param node node to free
*/
void sp_free_node(SP_NODE *node) {
if(!node)
return;
if(node->op_type == SP_OPTYPE_ANDOR) {
if(node->left.node) {
sp_free_node(node->left.node);
node->left.node = NULL;
}
if(node->right.node) {
sp_free_node(node->right.node);
node->right.node = NULL;
}
} else {
if(node->left.field) {
free(node->left.field);
node->left.field = NULL;
}
if(node->op_type == SP_OPTYPE_STRING) {
if(node->right.cvalue) {
free(node->right.cvalue);
node->right.cvalue = NULL;
}
}
}
free(node);
}
/** /**
* dispose of an initialized tree * dispose of an initialized tree
@ -680,6 +833,12 @@ int sp_dispose(PARSETREE tree) {
if(tree->term) if(tree->term)
free(tree->term); free(tree->term);
if(tree->token.token_id & 0x2000)
free(tree->token.data.cvalue);
if(tree->next_token.token_id & 0x2000)
free(tree->next_token.data.cvalue);
free(tree); free(tree);
return 1; return 1;
} }
@ -689,7 +848,8 @@ int sp_dispose(PARSETREE tree) {
* if there was an error in a previous action (parsing?) * if there was an error in a previous action (parsing?)
* then return that error to the client. This does not * then return that error to the client. This does not
* clear the error condition -- multiple calls to sp_geterror * clear the error condition -- multiple calls to sp_geterror
* will return the same value. * will return the same value. Also, if you want to keep an error,
* you must strdup it before it disposing the parse tree...
* *
* memory handling is done on the smart-parser side. * memory handling is done on the smart-parser side.
* *