/* This routine will create the value object */ static exprVal *exprCreateVal(char *name, EXPRTYPE val, EXPRTYPE * addr) { exprVal *tmp; char *vtmp; /* Name already tested in exprValListAdd */ /* Create it */ tmp = exprAllocMem(sizeof(exprVal)); if (tmp == NULL) return NULL; /* Allocate space for the name */ vtmp = exprAllocMem(strlen(name) + 1); if (vtmp == NULL) { exprFreeMem(tmp); return NULL; } /* Copy the data over */ strcpy(vtmp, name); tmp->vname = vtmp; tmp->vval = val; tmp->vptr = addr; return tmp; }
/* This routine will create the function object */ exprFunc *exprCreateFunc(exprFuncType ptr, char *name, int min, int max, int refmin, int refmax) { exprFunc *tmp; char *vtmp; /* Make sure the name is valid */ if(!exprValidIdent(name)) return NULL; /* Create it */ tmp = exprAllocMem(sizeof(exprFunc)); if(tmp == NULL) return NULL; /* Allocate space for the name */ vtmp = exprAllocMem(strlen(name) + 1); if(vtmp == NULL) { exprFreeMem(tmp); return NULL; } /* Set the memory to zero */ memset(tmp, 0, sizeof(exprFunc)); /* Copy the data over */ strcpy(vtmp, name); tmp->fname = vtmp; tmp->fptr = ptr; tmp->min = min; tmp->max = max; tmp->refmin = refmin; tmp->refmax = refmax; return tmp; }
/* This function creates the value list, */ int exprValListCreate(exprValList ** vlist) { exprValList *tmp; if (vlist == NULL) return EXPR_ERROR_NULLPOINTER; *vlist = NULL; /* Set to NULL initially */ tmp = exprAllocMem(sizeof(exprValList)); if (tmp == NULL) return EXPR_ERROR_MEMORY; /* Could not allocate memory */ /* Update pointer */ *vlist = tmp; return EXPR_ERROR_NOERROR; }
/* This function creates the function list, */ int exprFuncListCreate(exprFuncList **f) { exprFuncList *tmp; if(f == NULL) return EXPR_ERROR_NULLPOINTER; *f = NULL; /* Set to NULL initially */ tmp = exprAllocMem(sizeof(exprFuncList)); if(tmp == NULL) return EXPR_ERROR_MEMORY; /* Could not allocate memory */ /* Clear memory */ memset(tmp, 0, sizeof(exprFuncList)); *f = tmp; return EXPR_ERROR_NOERROR; }
/* Allocate a list of nodes */ exprNode *exprAllocNodes(size_t count) { return exprAllocMem(count * sizeof(exprNode)); }
/* This converts an expression string to a token list */ int exprStringToTokenList(exprObj *obj, char *expr, exprToken **tokens, int *count) { int found; exprToken *list; int pass; int pos, len; int tpos; int comment; /* Is a comment active */ int start, ilen; char buf[EXPR_MAXIDENTSIZE + 1]; /* Set initial variables */ found = 0; tpos = 0; list = NULL; comment = 0; *tokens = NULL; *count = 0; /* Check string length */ len = strlen(expr); if(len == 0) return EXPR_ERROR_EMPTYEXPR; /* Two passes, one to count, one to tokenize */ for(pass = 0; pass <= 1; pass++) { for(pos = 0; pos < len; pos++) { switch(expr[pos]) { /* Comment */ case '#': { /* Only set it if a comment is not already active */ if(!comment) comment = 1; break; } /* Newline characters turn off comments */ case '\r': case '\n': { /* If a comment is active, unset it */ if(comment) comment = 0; break; } /* Open parenthesis */ case '(': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_OPAREN; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Close parenthesis */ case ')': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_CPAREN; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Plus */ case '+': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_PLUS; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Hyphen */ case '-': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_HYPHEN; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Asterisk */ case '*': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_ASTERISK; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Forward slash */ case '/': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_FSLASH; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Hat */ case '^': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_HAT; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Ampersand */ case '&': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_AMPERSAND; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Semicolon */ case ';': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_SEMICOLON; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Comma */ case ',': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_COMMA; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Equal sign */ case '=': { if(!comment) { if(pass == 0) found++; else { list[tpos].type = EXPR_TOKEN_EQUAL; list[tpos].start = pos; list[tpos].end = pos; tpos++; } } break; } /* Identifiers and values */ default: { if(!comment) { if(expr[pos] == '.' || isdigit(expr[pos])) { /* Value */ start = pos; /* Find digits before a period */ while(isdigit(expr[pos])) pos++; /* Find a period */ if(expr[pos] == '.') pos++; /* Find digits after a period */ while(isdigit(expr[pos])) pos++; /* pos is AFTER last item, back up */ pos--; if(pass == 0) found++; else { ilen = pos - start + 1; /* Is the value to large */ if(ilen > EXPR_MAXIDENTSIZE) { obj->starterr = start; obj->enderr = pos; exprFreeTokenList(list, found); return EXPR_ERROR_BADIDENTIFIER; } /* Create value token */ strncpy(buf, expr + start, ilen); buf[ilen] = '\0'; list[tpos].type = EXPR_TOKEN_VALUE; list[tpos].start = start; list[tpos].end = pos; list[tpos].data.val = (EXPRTYPE)atof(buf); tpos++; } } else if(expr[pos] == '_' || isalpha(expr[pos])) { /* Identifier */ start = pos; /* Find rest of identifier */ while(expr[pos] == '_' || isalnum(expr[pos])) pos++; /* pos is AFTER last item, back up */ pos--; if(pass == 0) found++; else { ilen = pos - start + 1; /* Is the value to large */ if(ilen > EXPR_MAXIDENTSIZE) { obj->starterr = start; obj->enderr = pos; exprFreeTokenList(list, found); return EXPR_ERROR_BADIDENTIFIER; } /* Create value token */ strncpy(buf, expr + start, ilen); buf[ilen] = '\0'; /* Allocate memory for identifier */ list[tpos].data.str = exprAllocMem(ilen + 1); if(list[tpos].data.str == NULL) { exprFreeTokenList(list, found); return EXPR_ERROR_MEMORY; } list[tpos].type = EXPR_TOKEN_IDENTIFIER; list[tpos].start = start; list[tpos].end = pos; strcpy(list[tpos].data.str, buf); tpos++; } } else if(isspace(expr[pos])) { /* Spaces are ignored, do nothing */ } else { /* Unknown */ obj->starterr = obj->enderr = pos; exprFreeTokenList(list, found); return EXPR_ERROR_INVALIDCHAR; } } break; } } } /* If pass is 0, allocate memory for next pass */ if(pass == 0) { /* First, make sure all comments were ended */ if(comment) comment = 0; /* Make sure the expression is not empty */ if(found == 0) return EXPR_ERROR_EMPTYEXPR; /* Allocate memory for token list */ list = exprAllocMem(found * sizeof(exprToken)); if(list == NULL) return EXPR_ERROR_MEMORY; tpos = 0; } } *count = found; *tokens = list; return EXPR_ERROR_NOERROR; }
/* Function will parse a call to a function */ int exprInternalParseFunction(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int p1, int p2) { int pos; int num, cur; int refnum, refcur; int plevel = 0; int lv, err; exprNode *tmp; exprFuncType fptr; int argmin, argmax; int refargmin, refargmax; int type; exprFuncList *l; exprValList *vars; EXPRTYPE *addr; EXPRTYPE **reftmp; /* We should have a function list */ l = exprGetFuncList(obj); if(l == NULL) return EXPR_ERROR_NOSUCHFUNCTION; /* check paren. location */ if(p2 <= p1) return EXPR_ERROR_SYNTAX; /* second paren. should not be after the end */ if(p2 > end) return EXPR_ERROR_SYNTAX; /* Item before parenthesis should be an identifier */ if(tokens[p1 - 1].type != EXPR_TOKEN_IDENTIFIER) { obj->starterr = tokens[p1 - 1].start; obj->enderr = tokens[p1].end; return EXPR_ERROR_SYNTAX; } /* Look up the function */ err = exprFuncListGet(l, tokens[p1 - 1].data.str, &fptr, &type, &argmin, &argmax, &refargmin, &refargmax); if(err != EXPR_ERROR_NOERROR) { if(err == EXPR_ERROR_NOTFOUND) { obj->starterr = tokens[p1 - 1].start; obj->enderr = tokens[p1 - 1].end; return EXPR_ERROR_NOSUCHFUNCTION; } else return err; } /* Make sure the function exists */ if(fptr == NULL && type == 0) { obj->starterr = tokens[p1 - 1].start; obj->enderr = tokens[p1 - 1].end; return EXPR_ERROR_NOSUCHFUNCTION; } /* Count arguments */ if(p2 == p1 + 1) { num = 0; refnum = 0; } else { num = 1; refnum = 0; /* count commas */ for(pos = p1 + 1; pos < p2; pos++) { switch(tokens[pos].type) { case EXPR_TOKEN_OPAREN: plevel++; break; case EXPR_TOKEN_CPAREN: plevel--; if(plevel < 0) { obj->starterr = tokens[pos].start; obj->enderr = tokens[pos].end; return EXPR_ERROR_UNMATCHEDPAREN; } break; case EXPR_TOKEN_COMMA: /* Found comma */ if(plevel == 0) num++; break; case EXPR_TOKEN_AMPERSAND: /* Found reference mark */ if(plevel == 0) { /* This may only occur after the open parenthesis or comma */ if(tokens[pos - 1].type == EXPR_TOKEN_OPAREN || tokens[pos - 1].type == EXPR_TOKEN_COMMA) refnum++; else return EXPR_ERROR_SYNTAX; } break; } } /* plevel should be zero */ if(plevel != 0) return EXPR_ERROR_UNMATCHEDPAREN; } /* We now have the number of total arguments and number of ref arguments. Get number of normal arguments */ num = num - refnum; /* Make sure number of arguments is correct */ /* Here we make sure the limits are greater or equal to zero because any negative number could be used to specify no limit */ if(argmin >= 0 && num < argmin) { obj->starterr = tokens[p1 - 1].start; obj->enderr = tokens[p2].end; return EXPR_ERROR_BADNUMBERARGUMENTS; } if(argmax >= 0 && num > argmax) { obj->starterr = tokens[p1 - 1].start; obj->enderr = tokens[p2].end; return EXPR_ERROR_BADNUMBERARGUMENTS; } if(refargmin >= 0 && refnum < refargmin) { obj->starterr = tokens[p1 - 1].start; obj->enderr = tokens[p2].end; return EXPR_ERROR_BADNUMBERARGUMENTS; } if(refargmax >= 0 && refnum > refargmax) { obj->starterr = tokens[p1 - 1].start; obj->enderr = tokens[p2].end; return EXPR_ERROR_BADNUMBERARGUMENTS; } /* Set tmp to null in case of no arguments */ tmp = NULL; reftmp = NULL; if(num > 0) { /* Allocate subnodes */ tmp = exprAllocNodes(num); if(tmp == NULL) return EXPR_ERROR_MEMORY; } if(refnum > 0) { /* Allocate ref pointers */ reftmp = exprAllocMem(sizeof(EXPRTYPE*) * refnum); if(reftmp == NULL) { exprFreeMem(tmp); return EXPR_ERROR_MEMORY; } } /* Set this node's data */ node->type = EXPR_NODETYPE_FUNCTION; node->data.function.fptr = fptr; node->data.function.nodecount = num; node->data.function.nodes = tmp; node->data.function.refcount = refnum; node->data.function.refs = reftmp; node->data.function.type = type; /* parse each subnode */ if(num + refnum > 0) { plevel = 0; cur = 0; refcur = 0; lv = p1 + 1; /* look for commas if more than 1 arg */ if(num + refnum > 1) { for(pos = p1 + 1; pos < p2; pos++) { switch(tokens[pos].type) { case EXPR_TOKEN_OPAREN: plevel++; break; case EXPR_TOKEN_CPAREN: plevel--; break; /* Already checked paren nesting above */ case EXPR_TOKEN_COMMA: /* Found comma */ if(plevel == 0) { /* parse inside */ if(tokens[lv].type == EXPR_TOKEN_AMPERSAND) { if(lv != pos - 2) { obj->starterr = tokens[lv].start; obj->enderr = tokens[pos].end; return EXPR_ERROR_SYNTAX; } /* It is a reference */ if(tokens[lv + 1].type != EXPR_TOKEN_IDENTIFIER) { obj->starterr = tokens[lv].start; obj->enderr = tokens[lv + 1].end; return EXPR_ERROR_SYNTAX; } /* Make sure it is not a constant */ vars = exprGetConstList(obj); if(vars) { exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); if(addr) { obj->starterr = tokens[lv].start; obj->enderr = tokens[lv + 1].start; return EXPR_ERROR_REFCONSTANT; } } /* Get variable list */ vars = exprGetVarList(obj); if(vars == NULL) return EXPR_ERROR_NOVARLIST; /* Get variable address */ exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); if(addr == NULL) { /* Add variable to list */ exprValListAdd(vars, tokens[lv + 1].data.str, 0.0); /* Try to get address again */ exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); if(addr == NULL) return EXPR_ERROR_MEMORY; /* Could not add variable */ } /* Set reference item */ reftmp[refcur] = addr; /* increase ref arg number and lv position*/ refcur++; lv = pos + 1; } else { err = exprInternalParse(obj, &(tmp[cur]), tokens, lv, pos - 1); if(err != EXPR_ERROR_NOERROR) return err; /* increase arg number and lv position*/ lv = pos + 1; cur++; } } break; } } } /* lv should point after the last comma, or open paren. if only 1 arg */ if(tokens[lv].type == EXPR_TOKEN_AMPERSAND) { if(lv != p2 - 2) { obj->starterr = tokens[lv].start; obj->enderr = tokens[p2].end; return EXPR_ERROR_SYNTAX; } /* It is a reference */ if(tokens[lv + 1].type != EXPR_TOKEN_IDENTIFIER) { obj->starterr = tokens[lv].start; obj->enderr = tokens[lv + 1].end; return EXPR_ERROR_SYNTAX; } /* Make sure it is not a constant */ vars = exprGetConstList(obj); if(vars) { exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); if(addr) { obj->starterr = tokens[lv].start; obj->enderr = tokens[lv + 1].start; return EXPR_ERROR_REFCONSTANT; } } /* Get variable list */ vars = exprGetVarList(obj); if(vars == NULL) return EXPR_ERROR_NOVARLIST; /* Get variable address */ exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); if(addr == NULL) { /* Add variable to list */ exprValListAdd(vars, tokens[lv + 1].data.str, 0.0); /* Try to get address again */ exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); if(addr == NULL) return EXPR_ERROR_MEMORY; /* Could not add variable */ } /* Set reference item */ reftmp[refcur] = addr; } else { err = exprInternalParse(obj, &(tmp[cur]), tokens, lv, p2 - 1); if(err != EXPR_ERROR_NOERROR) return err; } } return EXPR_ERROR_NOERROR; }