📄 exprnpsr.c
字号:
/*******************************************************/ /* "C" Language Integrated Production System */ /* */ /* CLIPS Version 6.24 06/05/06 */ /* */ /* EXPRESSION PARSER MODULE */ /*******************************************************//*************************************************************//* Purpose: Provides routines for parsing expressions. *//* *//* Principal Programmer(s): *//* Gary D. Riley *//* *//* Contributing Programmer(s): *//* Brian L. Donnell *//* *//* Revision History: *//* 6.23: Changed name of variable exp to theExp *//* because of Unix compiler warnings of shadowed *//* definitions. *//* *//* 6.24: Renamed BOOLEAN macro type to intBool. *//* *//* 6.30: Module specifier can be used within an *//* expression to refer to a deffunction or *//* defgeneric exported by the specified module, *//* but not necessarily imported by the current *//* module. *//*************************************************************/#define _EXPRNPSR_SOURCE_#include "setup.h"#include <stdio.h>#define _STDIO_INCLUDED_#include <stdlib.h>#include <string.h>#include <ctype.h>#include "constant.h"#include "envrnmnt.h"#include "router.h"#include "strngrtr.h"#include "scanner.h"#include "memalloc.h"#include "argacces.h"#include "prntutil.h"#include "cstrnchk.h"#include "extnfunc.h"#include "exprnpsr.h"#include "modulutl.h"#include "prcdrfun.h"#if DEFRULE_CONSTRUCT#include "network.h"#endif#if DEFGENERIC_CONSTRUCT#include "genrccom.h"#endif#if DEFFUNCTION_CONSTRUCT#include "dffnxfun.h"#endif#if (! RUN_TIME)/***************************************************//* Function0Parse: Parses a function. Assumes that *//* none of the function has been parsed yet. *//***************************************************/globle struct expr *Function0Parse( void *theEnv, char *logicalName) { struct token theToken; struct expr *top; /*=================================*/ /* All functions begin with a '('. */ /*=================================*/ GetToken(theEnv,logicalName,&theToken); if (theToken.type != LPAREN) { SyntaxErrorMessage(theEnv,"function calls"); return(NULL); } /*=================================*/ /* Parse the rest of the function. */ /*=================================*/ top = Function1Parse(theEnv,logicalName); return(top); }/*******************************************************//* Function1Parse: Parses a function. Assumes that the *//* opening left parenthesis has already been parsed. *//*******************************************************/globle struct expr *Function1Parse( void *theEnv, char *logicalName) { struct token theToken; struct expr *top; /*========================*/ /* Get the function name. */ /*========================*/ GetToken(theEnv,logicalName,&theToken); if (theToken.type != SYMBOL) { PrintErrorID(theEnv,"EXPRNPSR",1,TRUE); EnvPrintRouter(theEnv,WERROR,"A function name must be a symbol\n"); return(NULL); } /*=================================*/ /* Parse the rest of the function. */ /*=================================*/ top = Function2Parse(theEnv,logicalName,ValueToString(theToken.value)); return(top); }/****************************************************//* Function2Parse: Parses a function. Assumes that *//* the opening left parenthesis and function name *//* have already been parsed. *//****************************************************/globle struct expr *Function2Parse( void *theEnv, char *logicalName, char *name) { struct FunctionDefinition *theFunction; struct expr *top; int moduleSpecified = FALSE; unsigned position; struct symbolHashNode *moduleName, *constructName;#if DEFGENERIC_CONSTRUCT void *gfunc;#endif#if DEFFUNCTION_CONSTRUCT void *dptr;#endif /*=========================================================*/ /* Module specification cannot be used in a function call. */ /*=========================================================*/ if ((position = FindModuleSeparator(name)) != FALSE) { moduleName = ExtractModuleName(theEnv,position,name); constructName = ExtractConstructName(theEnv,position,name); moduleSpecified = TRUE; } /*================================*/ /* Has the function been defined? */ /*================================*/ theFunction = FindFunction(theEnv,name);#if DEFGENERIC_CONSTRUCT if (moduleSpecified) { if (ConstructExported(theEnv,"defgeneric",moduleName,constructName) || EnvGetCurrentModule(theEnv) == EnvFindDefmodule(theEnv,ValueToString(moduleName))) { gfunc = (void *) EnvFindDefgeneric(theEnv,name); } else { gfunc = NULL; } } else { gfunc = (void *) LookupDefgenericInScope(theEnv,name); }#endif#if DEFFUNCTION_CONSTRUCT if ((theFunction == NULL)#if DEFGENERIC_CONSTRUCT && (gfunc == NULL)#endif ) if (moduleSpecified) { if (ConstructExported(theEnv,"deffunction",moduleName,constructName) || EnvGetCurrentModule(theEnv) == EnvFindDefmodule(theEnv,ValueToString(moduleName))) { dptr = (void *) EnvFindDeffunction(theEnv,name); } else { dptr = NULL; } } else { dptr = (void *) LookupDeffunctionInScope(theEnv,name); } else dptr = NULL;#endif /*=============================*/ /* Define top level structure. */ /*=============================*/#if DEFFUNCTION_CONSTRUCT if (dptr != NULL) top = GenConstant(theEnv,PCALL,dptr); else#endif#if DEFGENERIC_CONSTRUCT if (gfunc != NULL) top = GenConstant(theEnv,GCALL,gfunc); else#endif if (theFunction != NULL) top = GenConstant(theEnv,FCALL,theFunction); else { PrintErrorID(theEnv,"EXPRNPSR",3,TRUE); EnvPrintRouter(theEnv,WERROR,"Missing function declaration for "); EnvPrintRouter(theEnv,WERROR,name); EnvPrintRouter(theEnv,WERROR,".\n"); return(NULL); } /*=======================================================*/ /* Check to see if function has its own parsing routine. */ /*=======================================================*/ PushRtnBrkContexts(theEnv); ExpressionData(theEnv)->ReturnContext = FALSE; ExpressionData(theEnv)->BreakContext = FALSE;#if DEFGENERIC_CONSTRUCT || DEFFUNCTION_CONSTRUCT if (top->type == FCALL)#endif { if (theFunction->parser != NULL) { top = (*theFunction->parser)(theEnv,top,logicalName); PopRtnBrkContexts(theEnv); if (top == NULL) return(NULL); if (ReplaceSequenceExpansionOps(theEnv,top->argList,top,FindFunction(theEnv,"(expansion-call)"), FindFunction(theEnv,"expand$"))) { ReturnExpression(theEnv,top); return(NULL); } return(top); } } /*========================================*/ /* Default parsing routine for functions. */ /*========================================*/ top = CollectArguments(theEnv,top,logicalName); PopRtnBrkContexts(theEnv); if (top == NULL) return(NULL); if (ReplaceSequenceExpansionOps(theEnv,top->argList,top,FindFunction(theEnv,"(expansion-call)"), FindFunction(theEnv,"expand$"))) { ReturnExpression(theEnv,top); return(NULL); } /*============================================================*/ /* If the function call uses the sequence expansion operator, */ /* its arguments cannot be checked until runtime. */ /*============================================================*/ if (top->value == (void *) FindFunction(theEnv,"(expansion-call)")) { return(top); } /*============================*/ /* Check for argument errors. */ /*============================*/ if ((top->type == FCALL) && EnvGetStaticConstraintChecking(theEnv)) { if (CheckExpressionAgainstRestrictions(theEnv,top,theFunction->restrictions,name)) { ReturnExpression(theEnv,top); return(NULL); } }#if DEFFUNCTION_CONSTRUCT else if (top->type == PCALL) { if (CheckDeffunctionCall(theEnv,top->value,CountArguments(top->argList)) == FALSE) { ReturnExpression(theEnv,top); return(NULL); } }#endif /*========================*/ /* Return the expression. */ /*========================*/ return(top); }/*********************************************************************** NAME : ReplaceSequenceExpansionOps DESCRIPTION : Replaces function calls which have multifield references as arguments into a call to a special function which expands the multifield into single arguments at run-time. Multifield references which are not function arguments are errors INPUTS : 1) The expression 2) The current function call 3) The address of the internal H/L function (expansion-call) 4) The address of the H/L function expand$ RETURNS : FALSE if OK, TRUE on errors SIDE EFFECTS : Function call expressions modified, if necessary NOTES : Function calls which truly want a multifield to be passed need use only a single-field refernce (i.e. ? instead of $? - the $ is being treated as a special expansion operator) **********************************************************************/globle intBool ReplaceSequenceExpansionOps( void *theEnv, EXPRESSION *actions, EXPRESSION *fcallexp, void *expcall, void *expmult) { EXPRESSION *theExp; while (actions != NULL) { if ((ExpressionData(theEnv)->SequenceOpMode == FALSE) && (actions->type == MF_VARIABLE)) actions->type = SF_VARIABLE; if ((actions->type == MF_VARIABLE) || (actions->type == MF_GBL_VARIABLE) || (actions->value == expmult)) { if ((fcallexp->type != FCALL) ? FALSE : (((struct FunctionDefinition *) fcallexp->value)->sequenceuseok == FALSE)) { PrintErrorID(theEnv,"EXPRNPSR",4,FALSE); EnvPrintRouter(theEnv,WERROR,"$ Sequence operator not a valid argument for "); EnvPrintRouter(theEnv,WERROR,ValueToString(((struct FunctionDefinition *) fcallexp->value)->callFunctionName)); EnvPrintRouter(theEnv,WERROR,".\n"); return(TRUE); } if (fcallexp->value != expcall) { theExp = GenConstant(theEnv,fcallexp->type,fcallexp->value); theExp->argList = fcallexp->argList; theExp->nextArg = NULL; fcallexp->type = FCALL; fcallexp->value = expcall; fcallexp->argList = theExp; } if (actions->value != expmult) { theExp = GenConstant(theEnv,SF_VARIABLE,actions->value); if (actions->type == MF_GBL_VARIABLE) theExp->type = GBL_VARIABLE; actions->argList = theExp; actions->type = FCALL; actions->value = expmult; } } if (actions->argList != NULL) { if ((actions->type == GCALL) || (actions->type == PCALL) || (actions->type == FCALL)) theExp = actions; else theExp = fcallexp; if (ReplaceSequenceExpansionOps(theEnv,actions->argList,theExp,expcall,expmult)) return(TRUE); } actions = actions->nextArg; } return(FALSE); }/*************************************************//* PushRtnBrkContexts: Saves the current context *//* for the break/return functions. *//*************************************************/globle void PushRtnBrkContexts( void *theEnv) { SAVED_CONTEXTS *svtmp; svtmp = get_struct(theEnv,saved_contexts); svtmp->rtn = ExpressionData(theEnv)->ReturnContext; svtmp->brk = ExpressionData(theEnv)->BreakContext; svtmp->nxt = ExpressionData(theEnv)->svContexts; ExpressionData(theEnv)->svContexts = svtmp; }/***************************************************//* PopRtnBrkContexts: Restores the current context *//* for the break/return functions. *//***************************************************/globle void PopRtnBrkContexts( void *theEnv) { SAVED_CONTEXTS *svtmp; ExpressionData(theEnv)->ReturnContext = ExpressionData(theEnv)->svContexts->rtn; ExpressionData(theEnv)->BreakContext = ExpressionData(theEnv)->svContexts->brk; svtmp = ExpressionData(theEnv)->svContexts; ExpressionData(theEnv)->svContexts = ExpressionData(theEnv)->svContexts->nxt; rtn_struct(theEnv,saved_contexts,svtmp); }/*****************************************************************//* CheckExpressionAgainstRestrictions: Compares the arguments to *//* a function to the set of restrictions for that function to *//* determine if any incompatibilities exist. If so, the value *//* TRUE is returned, otherwise FALSE is returned. *//*****************************************************************/globle int CheckExpressionAgainstRestrictions( void *theEnv, struct expr *theExpression, char *restrictions, char *functionName) { char theChar[2]; int i = 0, j = 1; int number1, number2; int argCount; char defaultRestriction, argRestriction; struct expr *argPtr; int theRestriction; theChar[0] = '0'; theChar[1] = '\0'; /*============================================*/ /* If there are no restrictions, then there's */ /* no need to check the function. */ /*============================================*/ if (restrictions == NULL) return(FALSE); /*=========================================*/ /* Count the number of function arguments. */ /*=========================================*/ argCount = CountArguments(theExpression->argList); /*======================================*/ /* Get the minimum number of arguments. */ /*======================================*/ theChar[0] = restrictions[i++]; if (isdigit(theChar[0])) { number1 = atoi(theChar); } else if (theChar[0] == '*') { number1 = -1; } else { return(FALSE); } /*======================================*/ /* Get the maximum number of arguments. */ /*======================================*/ theChar[0] = restrictions[i++]; if (isdigit(theChar[0])) { number2 = atoi(theChar); } else if (theChar[0] == '*') { number2 = 10000; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -