/* This routine will free any child nodes, and then free itself */ static void exprValListFreeData(exprVal * val) { exprVal *next; while (val) { /* Remember the next */ next = val->next; /* Free name */ exprFreeMem(val->vname); /* Free ourself */ exprFreeMem(val); val = next; } }
/* This routine will free the value list */ int exprValListFree(exprValList * vlist) { /* Make sure it exists, if not it is not error */ if (vlist == NULL) return EXPR_ERROR_NOERROR; /* Free the nodes */ exprValListFreeData(vlist->head); /* Freethe container */ exprFreeMem(vlist); return EXPR_ERROR_NOERROR; }
/* This routine will free the function list */ int exprFuncListFree(exprFuncList *f) { /* Make sure it exists, if not it is not error */ if(f == NULL) return EXPR_ERROR_NOERROR; /* Free the nodes */ if(f->head) { exprFuncListFreeData(f->head); /* Freethe container */ exprFreeMem(f); } return EXPR_ERROR_NOERROR; }
/* 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; }
/* 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; }