📄 msgpass.c
字号:
/*******************************************************/
/* "C" Language Integrated Production System */
/* */
/* CLIPS Version 6.24 05/17/06 */
/* */
/* OBJECT MESSAGE DISPATCH CODE */
/*******************************************************/
/*************************************************************/
/* Purpose: */
/* */
/* Principal Programmer(s): */
/* Brian L. Donnell */
/* */
/* Contributing Programmer(s): */
/* */
/* Revision History: */
/* 6.23: Correction for FalseSymbol/TrueSymbol. DR0859 */
/* */
/* 6.24: Removed IMPERATIVE_MESSAGE_HANDLERS and */
/* AUXILIARY_MESSAGE_HANDLERS compilation flags. */
/* */
/* Renamed BOOLEAN macro type to intBool. */
/* */
/*************************************************************/
/* =========================================
*****************************************
EXTERNAL DEFINITIONS
=========================================
***************************************** */
#include "setup.h"
#if OBJECT_SYSTEM
#ifndef _STDIO_INCLUDED_
#include <stdio.h>
#define _STDIO_INCLUDED_
#endif
#include <stdlib.h>
#include "argacces.h"
#include "classcom.h"
#include "classfun.h"
#include "memalloc.h"
#include "constrct.h"
#include "envrnmnt.h"
#include "exprnpsr.h"
#include "insfun.h"
#include "msgcom.h"
#include "msgfun.h"
#include "multifld.h"
#include "prcdrfun.h"
#include "prccode.h"
#include "proflfun.h"
#include "router.h"
#include "strngfun.h"
#include "utility.h"
#include "commline.h"
#define _MSGPASS_SOURCE_
#include "msgpass.h"
#include "inscom.h"
/* =========================================
*****************************************
INTERNALLY VISIBLE FUNCTION HEADERS
=========================================
***************************************** */
static void PerformMessage(void *,DATA_OBJECT *,EXPRESSION *,SYMBOL_HN *);
static HANDLER_LINK *FindApplicableHandlers(void *,DEFCLASS *,SYMBOL_HN *);
static void CallHandlers(void *,DATA_OBJECT *);
static void EarlySlotBindError(void *,INSTANCE_TYPE *,DEFCLASS *,unsigned);
/* =========================================
*****************************************
EXTERNALLY VISIBLE FUNCTIONS
=========================================
***************************************** */
/*****************************************************
NAME : DirectMessage
DESCRIPTION : Plugs in given instance and
performs specified message
INPUTS : 1) Message symbolic name
2) The instance address
3) Address of DATA_OBJECT buffer
(NULL if don't care)
4) Message argument expressions
RETURNS : Nothing useful
SIDE EFFECTS : Side effects of message execution
NOTES : None
*****************************************************/
globle void DirectMessage(
void *theEnv,
SYMBOL_HN *msg,
INSTANCE_TYPE *ins,
DATA_OBJECT *resultbuf,
EXPRESSION *remargs)
{
EXPRESSION args;
DATA_OBJECT temp;
if (resultbuf == NULL)
resultbuf = &temp;
args.nextArg = remargs;
args.argList = NULL;
args.type = INSTANCE_ADDRESS;
args.value = (void *) ins;
PerformMessage(theEnv,resultbuf,&args,msg);
}
/***************************************************
NAME : EnvSend
DESCRIPTION : C Interface for sending messages to
instances
INPUTS : 1) The data object of the instance
2) The message name-string
3) The message arguments string
(Constants only)
4) Caller's buffer for result
RETURNS : Nothing useful
SIDE EFFECTS : Executes message and stores result
caller's buffer
NOTES : None
***************************************************/
globle void EnvSend(
void *theEnv,
DATA_OBJECT *idata,
char *msg,
char *args,
DATA_OBJECT *result)
{
int error;
EXPRESSION *iexp;
SYMBOL_HN *msym;
if ((EvaluationData(theEnv)->CurrentEvaluationDepth == 0) && (! CommandLineData(theEnv)->EvaluatingTopLevelCommand) &&
(EvaluationData(theEnv)->CurrentExpression == NULL))
{ PeriodicCleanup(theEnv,TRUE,FALSE); }
SetEvaluationError(theEnv,FALSE);
result->type = SYMBOL;
result->value = EnvFalseSymbol(theEnv);
msym = FindSymbolHN(theEnv,msg);
if (msym == NULL)
{
PrintNoHandlerError(theEnv,msg);
SetEvaluationError(theEnv,TRUE);
return;
}
iexp = GenConstant(theEnv,idata->type,idata->value);
iexp->nextArg = ParseConstantArguments(theEnv,args,&error);
if (error == TRUE)
{
ReturnExpression(theEnv,iexp);
SetEvaluationError(theEnv,TRUE);
return;
}
PerformMessage(theEnv,result,iexp,msym);
ReturnExpression(theEnv,iexp);
}
/*****************************************************
NAME : DestroyHandlerLinks
DESCRIPTION : Iteratively deallocates handler-links
INPUTS : The handler-link list
RETURNS : Nothing useful
SIDE EFFECTS : Deallocation of links
NOTES : None
*****************************************************/
globle void DestroyHandlerLinks(
void *theEnv,
HANDLER_LINK *mhead)
{
HANDLER_LINK *tmp;
while (mhead != NULL)
{
tmp = mhead;
mhead = mhead->nxt;
tmp->hnd->busy--;
DecrementDefclassBusyCount(theEnv,(void *) tmp->hnd->cls);
rtn_struct(theEnv,messageHandlerLink,tmp);
}
}
/***********************************************************************
NAME : SendCommand
DESCRIPTION : Determines the applicable handler(s) and sets up the
core calling frame. Then calls the core frame.
INPUTS : Caller's space for storing the result of the handler(s)
RETURNS : Nothing useful
SIDE EFFECTS : Any side-effects caused by the execution of handlers in
the core framework
NOTES : H/L Syntax : (send <instance> <hnd> <args>*)
***********************************************************************/
globle void SendCommand(
void *theEnv,
DATA_OBJECT *result)
{
EXPRESSION args;
SYMBOL_HN *msg;
DATA_OBJECT temp;
result->type = SYMBOL;
result->value = EnvFalseSymbol(theEnv);
if (EnvArgTypeCheck(theEnv,"send",2,SYMBOL,&temp) == FALSE)
return;
msg = (SYMBOL_HN *) temp.value;
/* =============================================
Get the instance or primitive for the message
============================================= */
args.type = GetFirstArgument()->type;
args.value = GetFirstArgument()->value;
args.argList = GetFirstArgument()->argList;
args.nextArg = GetFirstArgument()->nextArg->nextArg;
PerformMessage(theEnv,result,&args,msg);
}
/***************************************************
NAME : GetNthMessageArgument
DESCRIPTION : Returns the address of the nth
(starting at 1) which is an
argument of the current message
dispatch
INPUTS : None
RETURNS : The message argument
SIDE EFFECTS : None
NOTES : The active instance is always
stored as the first argument (0) in
the call frame of the message
***************************************************/
globle DATA_OBJECT *GetNthMessageArgument(
void *theEnv,
int n)
{
return(&ProceduralPrimitiveData(theEnv)->ProcParamArray[n]);
}
/*****************************************************
NAME : NextHandlerAvailable
DESCRIPTION : Determines if there the currently
executing handler can call a
shadowed handler
Used before calling call-next-handler
INPUTS : None
RETURNS : TRUE if shadow ready, FALSE otherwise
SIDE EFFECTS : None
NOTES : H/L Syntax: (next-handlerp)
*****************************************************/
globle int NextHandlerAvailable(
void *theEnv)
{
if (MessageHandlerData(theEnv)->CurrentCore == NULL)
return(FALSE);
if (MessageHandlerData(theEnv)->CurrentCore->hnd->type == MAROUND)
return((MessageHandlerData(theEnv)->NextInCore != NULL) ? TRUE : FALSE);
if ((MessageHandlerData(theEnv)->CurrentCore->hnd->type == MPRIMARY) && (MessageHandlerData(theEnv)->NextInCore != NULL))
return((MessageHandlerData(theEnv)->NextInCore->hnd->type == MPRIMARY) ? TRUE : FALSE);
return(FALSE);
}
/********************************************************
NAME : CallNextHandler
DESCRIPTION : This function allows around-handlers
to execute the rest of the core frame.
It also allows primary handlers
to execute shadowed primaries.
The original handler arguments are
left intact.
INPUTS : The caller's result-value buffer
RETURNS : Nothing useful
SIDE EFFECTS : The core frame is called and any
appropriate changes are made when
used in an around handler
See CallHandlers()
But when call-next-handler is called
from a primary, the same shadowed
primary is called over and over
again for repeated calls to
call-next-handler.
NOTES : H/L Syntax: (call-next-handler) OR
(override-next-handler <arg> ...)
********************************************************/
globle void CallNextHandler(
void *theEnv,
DATA_OBJECT *result)
{
EXPRESSION args;
int overridep;
HANDLER_LINK *oldNext,*oldCurrent;
#if PROFILING_FUNCTIONS
struct profileFrameInfo profileFrame;
#endif
SetpType(result,SYMBOL);
SetpValue(result,EnvFalseSymbol(theEnv));
EvaluationData(theEnv)->EvaluationError = FALSE;
if (EvaluationData(theEnv)->HaltExecution)
return;
if (NextHandlerAvailable(theEnv) == FALSE)
{
PrintErrorID(theEnv,"MSGPASS",1,FALSE);
EnvPrintRouter(theEnv,WERROR,"Shadowed message-handlers not applicable in current context.\n");
SetEvaluationError(theEnv,TRUE);
return;
}
if (EvaluationData(theEnv)->CurrentExpression->value == (void *) FindFunction(theEnv,"override-next-handler"))
{
overridep = 1;
args.type = ProceduralPrimitiveData(theEnv)->ProcParamArray[0].type;
if (args.type != MULTIFIELD)
args.value = (void *) ProceduralPrimitiveData(theEnv)->ProcParamArray[0].value;
else
args.value = (void *) &ProceduralPrimitiveData(theEnv)->ProcParamArray[0];
args.nextArg = GetFirstArgument();
args.argList = NULL;
PushProcParameters(theEnv,&args,CountArguments(&args),
ValueToString(MessageHandlerData(theEnv)->CurrentMessageName),"message",
UnboundHandlerErr);
if (EvaluationData(theEnv)->EvaluationError)
{
ProcedureFunctionData(theEnv)->ReturnFlag = FALSE;
return;
}
}
else
overridep = 0;
oldNext = MessageHandlerData(theEnv)->NextInCore;
oldCurrent = MessageHandlerData(theEnv)->CurrentCore;
if (MessageHandlerData(theEnv)->CurrentCore->hnd->type == MAROUND)
{
if (MessageHandlerData(theEnv)->NextInCore->hnd->type == MAROUND)
{
MessageHandlerData(theEnv)->CurrentCore = MessageHandlerData(theEnv)->NextInCore;
MessageHandlerData(theEnv)->NextInCore = MessageHandlerData(theEnv)->NextInCore->nxt;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -