📄 prccode.c
字号:
9) Special user data buffer to pass to variable
reference and bind replacement functions
RETURNS : A packed expression containing the body, NULL on
errors.
SIDE EFFECTS : Variable references replaced with runtime calls
to access the paramter and local variable array
NOTES : None
*************************************************************************/
globle EXPRESSION *ParseProcActions(
void *theEnv,
char *bodytype,
char *readSource,
struct token *tkn,
EXPRESSION *params,
SYMBOL_HN *wildcard,
int (*altvarfunc)(void *,EXPRESSION *,void *),
int (*altbindfunc)(void *,EXPRESSION *,void *),
int *lvarcnt,
void *userBuffer)
{
EXPRESSION *actions,*pactions;
/* ====================================================================
Clear parsed bind list - so that only local vars from this body will
be on it. The position of vars on thsi list are used to generate
indices into the LocalVarArray at runtime. The parsing of the
"bind" function adds vars to this list.
==================================================================== */
ClearParsedBindNames(theEnv);
actions = GroupActions(theEnv,readSource,tkn,TRUE,NULL,FALSE);
if (actions == NULL)
return(NULL);
/* ====================================================================
Replace any bind functions with special functions before replacing
any variable references. This allows those bind names to be removed
before they can be seen by variable replacement and thus generate
incorrect indices.
==================================================================== */
if (altbindfunc != NULL)
{
if (ReplaceProcBinds(theEnv,actions,altbindfunc,userBuffer))
{
ClearParsedBindNames(theEnv);
ReturnExpression(theEnv,actions);
return(NULL);
}
}
/* ======================================================================
The number of names left on the bind list is the number of local
vars for this procedure body. Replace all variable reference with
runtime access functions for ProcParamArray, LocalVarArray or
other special items, such as direct slot references, global variables,
or fact field references.
====================================================================== */
*lvarcnt = CountParsedBindNames(theEnv);
if (ReplaceProcVars(theEnv,bodytype,actions,params,wildcard,altvarfunc,userBuffer))
{
ClearParsedBindNames(theEnv);
ReturnExpression(theEnv,actions);
return(NULL);
}
/* =======================================================================
Normally, actions are grouped in a progn. If there is only one action,
the progn is unnecessary and can be removed. Also, the actions are
packed into a contiguous array to save on memory overhead. The
intermediate parsed bind names are freed to avoid tying up memory.
======================================================================= */
actions = CompactActions(theEnv,actions);
pactions = PackExpression(theEnv,actions);
ReturnExpression(theEnv,actions);
ClearParsedBindNames(theEnv);
return(pactions);
}
/*************************************************************************
NAME : ReplaceProcVars
DESCRIPTION : Examines an expression for variables
and replaces any that correspond to
procedure parameters or globals
with function calls that get these
variables' values at run-time.
For example, procedure arguments
are stored an array at run-time, so at
parse-time, parameter-references are replaced
with function calls referencing this array at
the appropriate position.
INPUTS : 1) The type of procedure being parsed
2) The expression-actions to be examined
3) The parameter list
4) The wildcard parameter symbol (NULL if none)
5) A pointer to a function to parse variables not
recognized by the standard parser
The function should accept the variable
expression and a generic pointer for special
data (can be NULL) as arguments. If the variable
is recognized, the function should modify the
expression to access this variable. Return 1
if recognized, 0 if not, -1 on errors
This argument can be NULL.
6) Data buffer to be passed to alternate parsing
function
RETURNS : FALSE if OK, TRUE on errors
SIDE EFFECTS : Variable references replaced with function calls
NOTES : This function works from the ParsedBindNames list in
SPCLFORM.C to access local binds. Make sure that
the list accurately reflects the binds by calling
ClearParsedBindNames(theEnv) before the parse of the body
in which variables are being replaced.
*************************************************************************/
globle int ReplaceProcVars(
void *theEnv,
char *bodytype,
EXPRESSION *actions,
EXPRESSION *parameterList,
SYMBOL_HN *wildcard,
int (*altvarfunc)(void *,EXPRESSION *,void *),
void *specdata)
{
int position,altcode;
intBool boundPosn;
EXPRESSION *arg_lvl,*altvarexp;
SYMBOL_HN *bindName;
PACKED_PROC_VAR pvar;
while (actions != NULL)
{
if (actions->type == SF_VARIABLE)
{
/*===============================================*/
/* See if the variable is in the parameter list. */
/*===============================================*/
bindName = (SYMBOL_HN *) actions->value;
position = FindProcParameter(bindName,parameterList,wildcard);
/*=============================================================*/
/* Check to see if the variable is bound within the procedure. */
/*=============================================================*/
boundPosn = SearchParsedBindNames(theEnv,bindName);
/*=============================================*/
/* If variable is not defined in the parameter */
/* list or as part of a bind action then... */
/*=============================================*/
if ((position == 0) && (boundPosn == 0))
{
/*================================================================*/
/* Check to see if the variable has a special access function, */
/* such as direct slot reference or a rule RHS pattern reference. */
/*================================================================*/
if ((altvarfunc != NULL) ? ((*altvarfunc)(theEnv,actions,specdata) != 1) : TRUE)
{
PrintErrorID(theEnv,"PRCCODE",3,TRUE);
EnvPrintRouter(theEnv,WERROR,"Undefined variable ");
EnvPrintRouter(theEnv,WERROR,ValueToString(bindName));
EnvPrintRouter(theEnv,WERROR," referenced in ");
EnvPrintRouter(theEnv,WERROR,bodytype);
EnvPrintRouter(theEnv,WERROR,".\n");
return(TRUE);
}
}
/*===================================================*/
/* Else if variable is defined in the parameter list */
/* and not rebound within the procedure then... */
/*===================================================*/
else if ((position > 0) && (boundPosn == 0))
{
actions->type = (unsigned short) ((bindName != wildcard) ? PROC_PARAM : PROC_WILD_PARAM);
actions->value = AddBitMap(theEnv,(void *) &position,(int) sizeof(int));
}
/*=========================================================*/
/* Else the variable is rebound within the procedure so... */
/*=========================================================*/
else
{
if (altvarfunc != NULL)
{
altvarexp = GenConstant(theEnv,actions->type,actions->value);
altcode = (*altvarfunc)(theEnv,altvarexp,specdata);
if (altcode == 0)
{
rtn_struct(theEnv,expr,altvarexp);
altvarexp = NULL;
}
else if (altcode == -1)
{
rtn_struct(theEnv,expr,altvarexp);
return(TRUE);
}
}
else
altvarexp = NULL;
actions->type = PROC_GET_BIND;
ClearBitString((void *) &pvar,(int) sizeof(PACKED_PROC_VAR));
pvar.first = boundPosn;
pvar.second = position;
pvar.secondFlag = (bindName != wildcard) ? 0 : 1;
actions->value = AddBitMap(theEnv,(void *) &pvar,(int) sizeof(PACKED_PROC_VAR));
actions->argList = GenConstant(theEnv,SYMBOL,(void *) bindName);
actions->argList->nextArg = altvarexp;
}
}
#if DEFGLOBAL_CONSTRUCT
else if (actions->type == GBL_VARIABLE)
{
if (ReplaceGlobalVariable(theEnv,actions) == FALSE)
return(-1);
}
#endif
if ((altvarfunc != NULL) ? ((*altvarfunc)(theEnv,actions,specdata) == -1) : FALSE)
return(TRUE);
if (actions->argList != NULL)
{
if (ReplaceProcVars(theEnv,bodytype,actions->argList,parameterList,
wildcard,altvarfunc,specdata))
return(TRUE);
/* ====================================================================
Check to see if this is a call to the bind function. If so (and the
second argument is a symbol) then it is a locally bound variable
(as opposed to a global).
Replace the call to "bind" with a call to PROC_BIND - the
special internal function for procedure local variables.
==================================================================== */
if ((actions->value == (void *) FindFunction(theEnv,"bind")) &&
(actions->argList->type == SYMBOL))
{
actions->type = PROC_BIND;
boundPosn = SearchParsedBindNames(theEnv,(SYMBOL_HN *) actions->argList->value);
actions->value = AddBitMap(theEnv,(void *) &boundPosn,(int) sizeof(intBool));
arg_lvl = actions->argList->nextArg;
rtn_struct(theEnv,expr,actions->argList);
actions->argList = arg_lvl;
}
}
actions = actions->nextArg;
}
return(FALSE);
}
#if DEFGENERIC_CONSTRUCT
/*****************************************************
NAME : GenProcWildcardReference
DESCRIPTION : Returns an expression to access the
wildcard parameter for a method
INPUTS : The starting index of the wildcard
RETURNS : An expression containing the wildcard
reference
SIDE EFFECTS : Expression allocated
NOTES : None
*****************************************************/
globle EXPRESSION *GenProcWildcardReference(
void *theEnv,
int theIndex)
{
return(GenConstant(theEnv,PROC_WILD_PARAM,AddBitMap(theEnv,(void *) &theIndex,(int) sizeof(int))));
}
#endif
#endif
/*******************************************************************
NAME : PushProcParameters
DESCRIPTION : Given a list of parameter expressions,
this function evaluates each expression
and stores the results in a contiguous
array of DATA_OBJECTS. Used in creating a new
ProcParamArray for the execution of a
procedure
The current arrays are saved on a stack.
INPUTS : 1) The paramter expression list
2) The number of parameters in the list
3) The name of the procedure for which
these parameters are being evaluated
4) The type of procedure
5) A pointer to a function to print out a trace
message about the currently executing
procedure when unbound variables are detected
at runtime (The function should take no
arguments and have no return value. The
function should print its synopsis to WERROR
and include the final carriage-return.)
RETURNS : Nothing useful
SIDE EFFECTS : Any side-effects of the evaluation of the
parameter expressions
DATA_OBJECT array allocated (deallocated on errors)
ProcParamArray set
NOTES : EvaluationError set on errors
*******************************************************************/
globle void PushProcParameters(
void *theEnv,
EXPRESSION *parameterList,
int numberOfParameters,
char *pname,
char *bodytype,
void (*UnboundErrFunc)(void *))
{
register PROC_PARAM_STACK *ptmp;
ptmp = get_struct(theEnv,ProcParamStack);
ptmp->ParamArray = ProceduralPrimitiveData(theEnv)->ProcParamArray;
ptmp->ParamArraySize = ProceduralPrimitiveData(theEnv)->ProcParamArraySize;
ptmp->UnboundErrFunc = ProceduralPrimitiveData(theEnv)->ProcUnboundErrFunc;
ptmp->nxt = ProceduralPrimitiveData(theEnv)->pstack;
ProceduralPrimitiveData(theEnv)->pstack = ptmp;
EvaluateProcParameters(theEnv,parameterList,numberOfParameters,pname,bodytype);
if (EvaluationData(theEnv)->EvaluationError)
{
ptmp = ProceduralPrimitiveData(theEnv)->pstack;
ProceduralPrimitiveData(theEnv)->pstack = ProceduralPrimitiveData(theEnv)->pstack->nxt;
rtn_struct(theEnv,ProcParamStack,ptmp);
return;
}
/* ================================================================
Record ProcParamExpressions and WildcardValue for previous frame
AFTER evaluating arguments for the new frame, because they could
have gone from NULL to non-NULL (if they were already non-NULL,
they would remain unchanged.)
================================================================ */
#if DEFGENERIC_CONSTRUCT
ptmp->ParamExpressions = ProceduralPrimitiveData(theEnv)->ProcParamExpressions;
ProceduralPrimitiveData(theEnv)->ProcParamExpressions = NULL;
#endif
ptmp->WildcardValue = ProceduralPrimitiveData(theEnv)->WildcardValue;
ProceduralPrimitiveData(theEnv)->WildcardValue = NULL;
ProceduralPrimitiveData(theEnv)->ProcUnboundErrFunc = UnboundErrFunc;
}
/******************************************************************
NAME : PopProcParameters
DESCRIPTION : Restores old procedure arrays
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -