📄 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. */
/* */
/*************************************************************/
#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;
#if DEFGENERIC_CONSTRUCT
void *gfunc;
#endif
#if DEFFUNCTION_CONSTRUCT
void *dptr;
#endif
/*=========================================================*/
/* Module specification cannot be used in a function call. */
/*=========================================================*/
if (FindModuleSeparator(name))
{
IllegalModuleSpecifierMessage(theEnv);
return(NULL);
}
/*================================*/
/* Has the function been defined? */
/*================================*/
theFunction = FindFunction(theEnv,name);
#if DEFGENERIC_CONSTRUCT
gfunc = (void *) LookupDefgenericInScope(theEnv,name);
#endif
#if DEFFUNCTION_CONSTRUCT
if ((theFunction == NULL)
#if DEFGENERIC_CONSTRUCT
&& (gfunc == NULL)
#endif
)
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; }
else
{ return(FALSE); }
/*============================================*/
/* Check for the correct number of arguments. */
/*============================================*/
if (number1 == number2)
{
if (argCount != number1)
{
ExpectedCountError(theEnv,functionName,EXACTLY,number1);
return(TRUE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -