1 /*******************************************************/
2 /* "C" Language Integrated Production System */
3 /* */
4 /* CLIPS Version 6.30 08/16/14 */
5 /* */
6 /* DEFTEMPLATE UTILITIES MODULE */
7 /*******************************************************/
8
9 /*************************************************************/
10 /* Purpose: Provides utility routines for deftemplates. */
11 /* */
12 /* Principal Programmer(s): */
13 /* Gary D. Riley */
14 /* */
15 /* Contributing Programmer(s): */
16 /* Brian L. Dantes */
17 /* */
18 /* Revision History: */
19 /* */
20 /* 6.23: Added support for templates maintaining their */
21 /* own list of facts. */
22 /* */
23 /* 6.24: Renamed BOOLEAN macro type to intBool. */
24 /* */
25 /* Added additional arguments to */
26 /* InvalidDeftemplateSlotMessage function. */
27 /* */
28 /* Added additional arguments to */
29 /* PrintTemplateFact function. */
30 /* */
31 /* 6.30: Support for long long integers. */
32 /* */
33 /* Used gensprintf instead of sprintf. */
34 /* */
35 /* Added const qualifiers to remove C++ */
36 /* deprecation warnings. */
37 /* */
38 /*************************************************************/
39
40 #define _TMPLTUTL_SOURCE_
41
42 #include "setup.h"
43
44 #if DEFTEMPLATE_CONSTRUCT
45
46 #include <stdio.h>
47
48 #define _STDIO_INCLUDED_
49
50 #include <string.h>
51
52 #include "extnfunc.h"
53 #include "memalloc.h"
54 #include "constrct.h"
55 #include "router.h"
56 #include "argacces.h"
57 #include "cstrnchk.h"
58 #include "envrnmnt.h"
59 #include "tmpltfun.h"
60 #include "tmpltpsr.h"
61 #include "modulutl.h"
62 #include "watch.h"
63 #include "sysdep.h"
64 #include "tmpltbsc.h"
65 #include "tmpltdef.h"
66
67 #include "tmpltutl.h"
68
69 /********************************************************/
70 /* InvalidDeftemplateSlotMessage: Generic error message */
71 /* for use when a specified slot name isn't defined */
72 /* in its corresponding deftemplate. */
73 /********************************************************/
InvalidDeftemplateSlotMessage(void * theEnv,const char * slotName,const char * deftemplateName,int printCR)74 globle void InvalidDeftemplateSlotMessage(
75 void *theEnv,
76 const char *slotName,
77 const char *deftemplateName,
78 int printCR)
79 {
80 PrintErrorID(theEnv,"TMPLTDEF",1,printCR);
81 EnvPrintRouter(theEnv,WERROR,"Invalid slot ");
82 EnvPrintRouter(theEnv,WERROR,slotName);
83 EnvPrintRouter(theEnv,WERROR," not defined in corresponding deftemplate ");
84 EnvPrintRouter(theEnv,WERROR,deftemplateName);
85 EnvPrintRouter(theEnv,WERROR,".\n");
86 }
87
88 /**********************************************************/
89 /* SingleFieldSlotCardinalityError: Generic error message */
90 /* used when an attempt is made to placed a multifield */
91 /* value into a single field slot. */
92 /**********************************************************/
SingleFieldSlotCardinalityError(void * theEnv,const char * slotName)93 globle void SingleFieldSlotCardinalityError(
94 void *theEnv,
95 const char *slotName)
96 {
97 PrintErrorID(theEnv,"TMPLTDEF",2,TRUE);
98 EnvPrintRouter(theEnv,WERROR,"The single field slot ");
99 EnvPrintRouter(theEnv,WERROR,slotName);
100 EnvPrintRouter(theEnv,WERROR," can only contain a single field value.\n");
101 }
102
103 /**********************************************************************/
104 /* MultiIntoSingleFieldSlotError: Determines if a multifield value is */
105 /* being placed into a single field slot of a deftemplate fact. */
106 /**********************************************************************/
MultiIntoSingleFieldSlotError(void * theEnv,struct templateSlot * theSlot,struct deftemplate * theDeftemplate)107 globle void MultiIntoSingleFieldSlotError(
108 void *theEnv,
109 struct templateSlot *theSlot,
110 struct deftemplate *theDeftemplate)
111 {
112 PrintErrorID(theEnv,"TMPLTFUN",2,TRUE);
113 EnvPrintRouter(theEnv,WERROR,"Attempted to assert a multifield value \n");
114 EnvPrintRouter(theEnv,WERROR,"into the single field slot ");
115 if (theSlot != NULL) EnvPrintRouter(theEnv,WERROR,theSlot->slotName->contents);
116 else EnvPrintRouter(theEnv,WERROR,"<<unknown>>");
117 EnvPrintRouter(theEnv,WERROR," of deftemplate ");
118 if (theDeftemplate != NULL) EnvPrintRouter(theEnv,WERROR,theDeftemplate->header.name->contents);
119 else EnvPrintRouter(theEnv,WERROR,"<<unknown>>");
120 EnvPrintRouter(theEnv,WERROR,".\n");
121
122 SetEvaluationError(theEnv,TRUE);
123 }
124
125 /**************************************************************/
126 /* CheckTemplateFact: Checks a fact to see if it violates any */
127 /* deftemplate type, allowed-..., or range specifications. */
128 /**************************************************************/
CheckTemplateFact(void * theEnv,struct fact * theFact)129 globle void CheckTemplateFact(
130 void *theEnv,
131 struct fact *theFact)
132 {
133 struct field *sublist;
134 int i;
135 struct deftemplate *theDeftemplate;
136 struct templateSlot *slotPtr;
137 DATA_OBJECT theData;
138 char thePlace[20];
139 int rv;
140
141 if (! EnvGetDynamicConstraintChecking(theEnv)) return;
142
143 sublist = theFact->theProposition.theFields;
144
145 /*========================================================*/
146 /* If the deftemplate corresponding to the first field of */
147 /* of the fact cannot be found, then the fact cannot be */
148 /* checked against the deftemplate format. */
149 /*========================================================*/
150
151 theDeftemplate = theFact->whichDeftemplate;
152 if (theDeftemplate == NULL) return;
153 if (theDeftemplate->implied) return;
154
155 /*=============================================*/
156 /* Check each of the slots of the deftemplate. */
157 /*=============================================*/
158
159 i = 0;
160 for (slotPtr = theDeftemplate->slotList;
161 slotPtr != NULL;
162 slotPtr = slotPtr->next)
163 {
164 /*================================================*/
165 /* Store the slot value in the appropriate format */
166 /* for a call to the constraint checking routine. */
167 /*================================================*/
168
169 if (slotPtr->multislot == FALSE)
170 {
171 theData.type = sublist[i].type;
172 theData.value = sublist[i].value;
173 i++;
174 }
175 else
176 {
177 theData.type = MULTIFIELD;
178 theData.value = (void *) sublist[i].value;
179 SetDOBegin(theData,1);
180 SetDOEnd(theData,((struct multifield *) sublist[i].value)->multifieldLength);
181 i++;
182 }
183
184 /*=============================================*/
185 /* Call the constraint checking routine to see */
186 /* if a constraint violation occurred. */
187 /*=============================================*/
188
189 rv = ConstraintCheckDataObject(theEnv,&theData,slotPtr->constraints);
190 if (rv != NO_VIOLATION)
191 {
192 gensprintf(thePlace,"fact f-%-5lld ",theFact->factIndex);
193
194 PrintErrorID(theEnv,"CSTRNCHK",1,TRUE);
195 EnvPrintRouter(theEnv,WERROR,"Slot value ");
196 PrintDataObject(theEnv,WERROR,&theData);
197 EnvPrintRouter(theEnv,WERROR," ");
198 ConstraintViolationErrorMessage(theEnv,NULL,thePlace,FALSE,0,slotPtr->slotName,
199 0,rv,slotPtr->constraints,TRUE);
200 SetHaltExecution(theEnv,TRUE);
201 return;
202 }
203 }
204
205 return;
206 }
207
208 /***********************************************************************/
209 /* CheckRHSSlotTypes: Checks the validity of a change to a slot as the */
210 /* result of an assert, modify, or duplicate command. This checking */
211 /* is performed statically (i.e. when the command is being parsed). */
212 /***********************************************************************/
CheckRHSSlotTypes(void * theEnv,struct expr * rhsSlots,struct templateSlot * slotPtr,const char * thePlace)213 globle intBool CheckRHSSlotTypes(
214 void *theEnv,
215 struct expr *rhsSlots,
216 struct templateSlot *slotPtr,
217 const char *thePlace)
218 {
219 int rv;
220 const char *theName;
221
222 if (EnvGetStaticConstraintChecking(theEnv) == FALSE) return(TRUE);
223 rv = ConstraintCheckExpressionChain(theEnv,rhsSlots,slotPtr->constraints);
224 if (rv != NO_VIOLATION)
225 {
226 if (rv != CARDINALITY_VIOLATION) theName = "A literal slot value";
227 else theName = "Literal slot values";
228 ConstraintViolationErrorMessage(theEnv,theName,thePlace,TRUE,0,
229 slotPtr->slotName,0,rv,slotPtr->constraints,TRUE);
230 return(0);
231 }
232
233 return(1);
234 }
235
236 /*********************************************************/
237 /* GetNthSlot: Given a deftemplate and an integer index, */
238 /* returns the nth slot of a deftemplate. */
239 /*********************************************************/
GetNthSlot(struct deftemplate * theDeftemplate,int position)240 globle struct templateSlot *GetNthSlot(
241 struct deftemplate *theDeftemplate,
242 int position)
243 {
244 struct templateSlot *slotPtr;
245 int i = 0;
246
247 slotPtr = theDeftemplate->slotList;
248 while (slotPtr != NULL)
249 {
250 if (i == position) return(slotPtr);
251 slotPtr = slotPtr->next;
252 i++;
253 }
254
255 return(NULL);
256 }
257
258 /*******************************************************/
259 /* FindSlotPosition: Finds the position of a specified */
260 /* slot in a deftemplate structure. */
261 /*******************************************************/
FindSlotPosition(struct deftemplate * theDeftemplate,SYMBOL_HN * name)262 globle int FindSlotPosition(
263 struct deftemplate *theDeftemplate,
264 SYMBOL_HN *name)
265 {
266 struct templateSlot *slotPtr;
267 int position;
268
269 for (slotPtr = theDeftemplate->slotList, position = 1;
270 slotPtr != NULL;
271 slotPtr = slotPtr->next, position++)
272 {
273 if (slotPtr->slotName == name)
274 { return(position); }
275 }
276
277 return(0);
278 }
279
280 /*******************************************************************/
281 /* PrintTemplateFact: Prints a fact using the deftemplate format. */
282 /* Returns TRUE if the fact was printed using this format, */
283 /* otherwise FALSE. */
284 /*******************************************************************/
PrintTemplateFact(void * theEnv,const char * logicalName,struct fact * theFact,int seperateLines,int ignoreDefaults)285 globle void PrintTemplateFact(
286 void *theEnv,
287 const char *logicalName,
288 struct fact *theFact,
289 int seperateLines,
290 int ignoreDefaults)
291 {
292 struct field *sublist;
293 int i;
294 struct deftemplate *theDeftemplate;
295 struct templateSlot *slotPtr;
296 DATA_OBJECT tempDO;
297 int slotPrinted = FALSE;
298
299 /*==============================*/
300 /* Initialize some information. */
301 /*==============================*/
302
303 theDeftemplate = theFact->whichDeftemplate;
304 sublist = theFact->theProposition.theFields;
305
306 /*=============================================*/
307 /* Print the relation name of the deftemplate. */
308 /*=============================================*/
309
310 EnvPrintRouter(theEnv,logicalName,"(");
311 EnvPrintRouter(theEnv,logicalName,theDeftemplate->header.name->contents);
312
313 /*===================================================*/
314 /* Print each of the field slots of the deftemplate. */
315 /*===================================================*/
316
317 slotPtr = theDeftemplate->slotList;
318
319 i = 0;
320 while (slotPtr != NULL)
321 {
322 /*=================================================*/
323 /* If we're ignoring slots with their original */
324 /* default value, check to see if the fact's slot */
325 /* value differs from the deftemplate default. */
326 /*=================================================*/
327
328 if (ignoreDefaults && (slotPtr->defaultDynamic == FALSE))
329 {
330 DeftemplateSlotDefault(theEnv,theDeftemplate,slotPtr,&tempDO,TRUE);
331
332 if (slotPtr->multislot == FALSE)
333 {
334 if ((GetType(tempDO) == sublist[i].type) &&
335 (GetValue(tempDO) == sublist[i].value))
336 {
337 i++;
338 slotPtr = slotPtr->next;
339 continue;
340 }
341 }
342 else if (MultifieldsEqual((struct multifield*) GetValue(tempDO),
343 (struct multifield *) sublist[i].value))
344 {
345 i++;
346 slotPtr = slotPtr->next;
347 continue;
348 }
349 }
350
351 /*===========================================*/
352 /* Print the opening parenthesis of the slot */
353 /* and the slot name. */
354 /*===========================================*/
355
356 if (! slotPrinted)
357 {
358 slotPrinted = TRUE;
359 EnvPrintRouter(theEnv,logicalName," ");
360 }
361
362 if (seperateLines)
363 { EnvPrintRouter(theEnv,logicalName,"\n "); }
364
365 EnvPrintRouter(theEnv,logicalName,"(");
366 EnvPrintRouter(theEnv,logicalName,slotPtr->slotName->contents);
367
368 /*======================================================*/
369 /* Print the value of the slot for a single field slot. */
370 /*======================================================*/
371
372 if (slotPtr->multislot == FALSE)
373 {
374 EnvPrintRouter(theEnv,logicalName," ");
375 PrintAtom(theEnv,logicalName,sublist[i].type,sublist[i].value);
376 }
377
378 /*==========================================================*/
379 /* Else print the value of the slot for a multi field slot. */
380 /*==========================================================*/
381
382 else
383 {
384 struct multifield *theSegment;
385
386 theSegment = (struct multifield *) sublist[i].value;
387 if (theSegment->multifieldLength > 0)
388 {
389 EnvPrintRouter(theEnv,logicalName," ");
390 PrintMultifield(theEnv,logicalName,(struct multifield *) sublist[i].value,
391 0,(long) theSegment->multifieldLength-1,FALSE);
392 }
393 }
394
395 /*============================================*/
396 /* Print the closing parenthesis of the slot. */
397 /*============================================*/
398
399 i++;
400 EnvPrintRouter(theEnv,logicalName,")");
401 slotPtr = slotPtr->next;
402 if (slotPtr != NULL) EnvPrintRouter(theEnv,logicalName," ");
403 }
404
405 EnvPrintRouter(theEnv,logicalName,")");
406 }
407
408 /***************************************************************************/
409 /* UpdateDeftemplateScope: Updates the scope flag of all the deftemplates. */
410 /***************************************************************************/
UpdateDeftemplateScope(void * theEnv)411 globle void UpdateDeftemplateScope(
412 void *theEnv)
413 {
414 struct deftemplate *theDeftemplate;
415 int moduleCount;
416 struct defmodule *theModule;
417 struct defmoduleItemHeader *theItem;
418
419 /*==================================*/
420 /* Loop through all of the modules. */
421 /*==================================*/
422
423 for (theModule = (struct defmodule *) EnvGetNextDefmodule(theEnv,NULL);
424 theModule != NULL;
425 theModule = (struct defmodule *) EnvGetNextDefmodule(theEnv,theModule))
426 {
427 /*======================================================*/
428 /* Loop through each of the deftemplates in the module. */
429 /*======================================================*/
430
431 theItem = (struct defmoduleItemHeader *)
432 GetModuleItem(theEnv,theModule,DeftemplateData(theEnv)->DeftemplateModuleIndex);
433
434 for (theDeftemplate = (struct deftemplate *) theItem->firstItem;
435 theDeftemplate != NULL ;
436 theDeftemplate = (struct deftemplate *) EnvGetNextDeftemplate(theEnv,theDeftemplate))
437 {
438 /*=======================================*/
439 /* If the deftemplate can be seen by the */
440 /* current module, then it is in scope. */
441 /*=======================================*/
442
443 if (FindImportedConstruct(theEnv,"deftemplate",theModule,
444 ValueToString(theDeftemplate->header.name),
445 &moduleCount,TRUE,NULL) != NULL)
446 { theDeftemplate->inScope = TRUE; }
447 else
448 { theDeftemplate->inScope = FALSE; }
449 }
450 }
451 }
452
453 /****************************************************************/
454 /* FindSlot: Finds a specified slot in a deftemplate structure. */
455 /****************************************************************/
FindSlot(struct deftemplate * theDeftemplate,SYMBOL_HN * name,short * whichOne)456 globle struct templateSlot *FindSlot(
457 struct deftemplate *theDeftemplate,
458 SYMBOL_HN *name,
459 short *whichOne)
460 {
461 struct templateSlot *slotPtr;
462
463 *whichOne = 1;
464 slotPtr = theDeftemplate->slotList;
465 while (slotPtr != NULL)
466 {
467 if (slotPtr->slotName == name)
468 { return(slotPtr); }
469 (*whichOne)++;
470 slotPtr = slotPtr->next;
471 }
472
473 *whichOne = -1;
474 return(NULL);
475 }
476
477 #if (! RUN_TIME) && (! BLOAD_ONLY)
478
479 /************************************************************/
480 /* CreateImpliedDeftemplate: Creates an implied deftemplate */
481 /* and adds it to the list of deftemplates. */
482 /************************************************************/
CreateImpliedDeftemplate(void * theEnv,SYMBOL_HN * deftemplateName,int setFlag)483 globle struct deftemplate *CreateImpliedDeftemplate(
484 void *theEnv,
485 SYMBOL_HN *deftemplateName,
486 int setFlag)
487 {
488 struct deftemplate *newDeftemplate;
489
490 newDeftemplate = get_struct(theEnv,deftemplate);
491 newDeftemplate->header.name = deftemplateName;
492 newDeftemplate->header.ppForm = NULL;
493 newDeftemplate->header.usrData = NULL;
494 newDeftemplate->slotList = NULL;
495 newDeftemplate->implied = setFlag;
496 newDeftemplate->numberOfSlots = 0;
497 newDeftemplate->inScope = 1;
498 newDeftemplate->patternNetwork = NULL;
499 newDeftemplate->factList = NULL;
500 newDeftemplate->lastFact = NULL;
501 newDeftemplate->busyCount = 0;
502 newDeftemplate->watch = FALSE;
503 newDeftemplate->header.next = NULL;
504
505 #if DEBUGGING_FUNCTIONS
506 if (EnvGetWatchItem(theEnv,"facts"))
507 { EnvSetDeftemplateWatch(theEnv,ON,(void *) newDeftemplate); }
508 #endif
509
510 newDeftemplate->header.whichModule = (struct defmoduleItemHeader *)
511 GetModuleItem(theEnv,NULL,DeftemplateData(theEnv)->DeftemplateModuleIndex);
512
513 AddConstructToModule(&newDeftemplate->header);
514 InstallDeftemplate(theEnv,newDeftemplate);
515
516 return(newDeftemplate);
517 }
518
519 #endif
520
521 #endif /* DEFTEMPLATE_CONSTRUCT */
522
523