1 /*******************************************************/
2 /* "C" Language Integrated Production System */
3 /* */
4 /* CLIPS Version 6.30 01/25/15 */
5 /* */
6 /* DEFTEMPLATE PARSER MODULE */
7 /*******************************************************/
8
9 /*************************************************************/
10 /* Purpose: Parses the deftemplate construct. */
11 /* */
12 /* Principal Programmer(s): */
13 /* Gary D. Riley */
14 /* */
15 /* Contributing Programmer(s): */
16 /* */
17 /* Revision History: */
18 /* */
19 /* 6.23: Added support for templates maintaining their */
20 /* own list of facts. */
21 /* */
22 /* 6.30: Removed conditional code for unsupported */
23 /* compilers/operating systems (IBM_MCW and */
24 /* MAC_MCW). */
25 /* */
26 /* GetConstructNameAndComment API change. */
27 /* */
28 /* Support for deftemplate slot facets. */
29 /* */
30 /* Added const qualifiers to remove C++ */
31 /* deprecation warnings. */
32 /* */
33 /* Changed find construct functionality so that */
34 /* imported modules are search when locating a */
35 /* named construct. */
36 /* */
37 /*************************************************************/
38
39 #define _TMPLTPSR_SOURCE_
40
41 #include "setup.h"
42
43 #if DEFTEMPLATE_CONSTRUCT
44
45 #include <stdio.h>
46 #define _STDIO_INCLUDED_
47 #include <string.h>
48
49 #include "constant.h"
50 #include "memalloc.h"
51 #include "symbol.h"
52 #include "scanner.h"
53 #include "exprnpsr.h"
54 #include "router.h"
55 #include "constrct.h"
56 #include "envrnmnt.h"
57 #include "factmngr.h"
58 #include "cstrnchk.h"
59 #include "cstrnpsr.h"
60 #include "cstrcpsr.h"
61 #if BLOAD || BLOAD_AND_BSAVE
62 #include "bload.h"
63 #endif
64 #include "default.h"
65 #include "pattern.h"
66 #include "watch.h"
67 #include "cstrnutl.h"
68
69 #include "tmpltdef.h"
70 #include "tmpltbsc.h"
71
72 #include "tmpltpsr.h"
73
74 /***************************************/
75 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
76 /***************************************/
77
78 #if (! RUN_TIME) && (! BLOAD_ONLY)
79 static struct templateSlot *SlotDeclarations(void *,const char *,struct token *);
80 static struct templateSlot *ParseSlot(void *,const char *,struct token *,struct templateSlot *);
81 static struct templateSlot *DefinedSlots(void *,const char *,SYMBOL_HN *,int,struct token *);
82 static intBool ParseFacetAttribute(void *,const char *,struct templateSlot *,intBool);
83 #endif
84
85 /*******************************************************/
86 /* ParseDeftemplate: Parses the deftemplate construct. */
87 /*******************************************************/
ParseDeftemplate(void * theEnv,const char * readSource)88 globle int ParseDeftemplate(
89 void *theEnv,
90 const char *readSource)
91 {
92 #if (! RUN_TIME) && (! BLOAD_ONLY)
93 SYMBOL_HN *deftemplateName;
94 struct deftemplate *newDeftemplate;
95 struct templateSlot *slots;
96 struct token inputToken;
97
98 /*================================================*/
99 /* Initialize pretty print and error information. */
100 /*================================================*/
101
102 DeftemplateData(theEnv)->DeftemplateError = FALSE;
103 SetPPBufferStatus(theEnv,ON);
104 FlushPPBuffer(theEnv);
105 SavePPBuffer(theEnv,"(deftemplate ");
106
107 /*==============================================================*/
108 /* Deftemplates can not be added when a binary image is loaded. */
109 /*==============================================================*/
110
111 #if BLOAD || BLOAD_AND_BSAVE
112 if ((Bloaded(theEnv) == TRUE) && (! ConstructData(theEnv)->CheckSyntaxMode))
113 {
114 CannotLoadWithBloadMessage(theEnv,"deftemplate");
115 return(TRUE);
116 }
117 #endif
118
119 /*=======================================================*/
120 /* Parse the name and comment fields of the deftemplate. */
121 /*=======================================================*/
122
123 #if DEBUGGING_FUNCTIONS
124 DeftemplateData(theEnv)->DeletedTemplateDebugFlags = 0;
125 #endif
126
127 deftemplateName = GetConstructNameAndComment(theEnv,readSource,&inputToken,"deftemplate",
128 EnvFindDeftemplateInModule,EnvUndeftemplate,"%",
129 TRUE,TRUE,TRUE,FALSE);
130 if (deftemplateName == NULL) return(TRUE);
131
132 if (ReservedPatternSymbol(theEnv,ValueToString(deftemplateName),"deftemplate"))
133 {
134 ReservedPatternSymbolErrorMsg(theEnv,ValueToString(deftemplateName),"a deftemplate name");
135 return(TRUE);
136 }
137
138 /*===========================================*/
139 /* Parse the slot fields of the deftemplate. */
140 /*===========================================*/
141
142 slots = SlotDeclarations(theEnv,readSource,&inputToken);
143 if (DeftemplateData(theEnv)->DeftemplateError == TRUE) return(TRUE);
144
145 /*==============================================*/
146 /* If we're only checking syntax, don't add the */
147 /* successfully parsed deftemplate to the KB. */
148 /*==============================================*/
149
150 if (ConstructData(theEnv)->CheckSyntaxMode)
151 {
152 ReturnSlots(theEnv,slots);
153 return(FALSE);
154 }
155
156 /*=====================================*/
157 /* Create a new deftemplate structure. */
158 /*=====================================*/
159
160 newDeftemplate = get_struct(theEnv,deftemplate);
161 newDeftemplate->header.name = deftemplateName;
162 newDeftemplate->header.next = NULL;
163 newDeftemplate->header.usrData = NULL;
164 newDeftemplate->slotList = slots;
165 newDeftemplate->implied = FALSE;
166 newDeftemplate->numberOfSlots = 0;
167 newDeftemplate->busyCount = 0;
168 newDeftemplate->watch = 0;
169 newDeftemplate->inScope = TRUE;
170 newDeftemplate->patternNetwork = NULL;
171 newDeftemplate->factList = NULL;
172 newDeftemplate->lastFact = NULL;
173 newDeftemplate->header.whichModule = (struct defmoduleItemHeader *)
174 GetModuleItem(theEnv,NULL,DeftemplateData(theEnv)->DeftemplateModuleIndex);
175
176 /*================================*/
177 /* Determine the number of slots. */
178 /*================================*/
179
180 while (slots != NULL)
181 {
182 newDeftemplate->numberOfSlots++;
183 slots = slots->next;
184 }
185
186 /*====================================*/
187 /* Store pretty print representation. */
188 /*====================================*/
189
190 if (EnvGetConserveMemory(theEnv) == TRUE)
191 { newDeftemplate->header.ppForm = NULL; }
192 else
193 { newDeftemplate->header.ppForm = CopyPPBuffer(theEnv); }
194
195 /*=======================================================================*/
196 /* If a template is redefined, then we want to restore its watch status. */
197 /*=======================================================================*/
198
199 #if DEBUGGING_FUNCTIONS
200 if ((BitwiseTest(DeftemplateData(theEnv)->DeletedTemplateDebugFlags,0)) || EnvGetWatchItem(theEnv,"facts"))
201 { EnvSetDeftemplateWatch(theEnv,ON,(void *) newDeftemplate); }
202 #endif
203
204 /*==============================================*/
205 /* Add deftemplate to the list of deftemplates. */
206 /*==============================================*/
207
208 AddConstructToModule(&newDeftemplate->header);
209
210 InstallDeftemplate(theEnv,newDeftemplate);
211
212 #else
213 #if MAC_XCD
214 #pragma unused(theEnv)
215 #endif
216 #endif
217
218 return(FALSE);
219 }
220
221 #if (! RUN_TIME) && (! BLOAD_ONLY)
222
223 /**************************************************************/
224 /* InstallDeftemplate: Increments all occurrences in the hash */
225 /* table of symbols found in an deftemplate and adds it to */
226 /* the hash table. */
227 /**************************************************************/
InstallDeftemplate(void * theEnv,struct deftemplate * theDeftemplate)228 globle void InstallDeftemplate(
229 void *theEnv,
230 struct deftemplate *theDeftemplate)
231 {
232 struct templateSlot *slotPtr;
233 struct expr *tempExpr;
234
235 IncrementSymbolCount(theDeftemplate->header.name);
236
237 for (slotPtr = theDeftemplate->slotList;
238 slotPtr != NULL;
239 slotPtr = slotPtr->next)
240 {
241 IncrementSymbolCount(slotPtr->slotName);
242 tempExpr = AddHashedExpression(theEnv,slotPtr->defaultList);
243 ReturnExpression(theEnv,slotPtr->defaultList);
244 slotPtr->defaultList = tempExpr;
245 tempExpr = AddHashedExpression(theEnv,slotPtr->facetList);
246 ReturnExpression(theEnv,slotPtr->facetList);
247 slotPtr->facetList = tempExpr;
248 slotPtr->constraints = AddConstraint(theEnv,slotPtr->constraints);
249 }
250 }
251
252 /********************************************************************/
253 /* SlotDeclarations: Parses the slot declarations of a deftemplate. */
254 /********************************************************************/
SlotDeclarations(void * theEnv,const char * readSource,struct token * inputToken)255 static struct templateSlot *SlotDeclarations(
256 void *theEnv,
257 const char *readSource,
258 struct token *inputToken)
259 {
260 struct templateSlot *newSlot, *slotList = NULL, *lastSlot = NULL;
261 struct templateSlot *multiSlot = NULL;
262
263 while (inputToken->type != RPAREN)
264 {
265 /*====================================================*/
266 /* Slots begin with a '(' followed by a slot keyword. */
267 /*====================================================*/
268
269 if (inputToken->type != LPAREN)
270 {
271 SyntaxErrorMessage(theEnv,"deftemplate");
272 ReturnSlots(theEnv,slotList);
273 ReturnSlots(theEnv,multiSlot);
274 DeftemplateData(theEnv)->DeftemplateError = TRUE;
275 return(NULL);
276 }
277
278 GetToken(theEnv,readSource,inputToken);
279 if (inputToken->type != SYMBOL)
280 {
281 SyntaxErrorMessage(theEnv,"deftemplate");
282 ReturnSlots(theEnv,slotList);
283 ReturnSlots(theEnv,multiSlot);
284 DeftemplateData(theEnv)->DeftemplateError = TRUE;
285 return(NULL);
286 }
287
288 /*=================*/
289 /* Parse the slot. */
290 /*=================*/
291
292 newSlot = ParseSlot(theEnv,readSource,inputToken,slotList);
293 if (DeftemplateData(theEnv)->DeftemplateError == TRUE)
294 {
295 ReturnSlots(theEnv,newSlot);
296 ReturnSlots(theEnv,slotList);
297 ReturnSlots(theEnv,multiSlot);
298 return(NULL);
299 }
300
301 /*===========================================*/
302 /* Attach the new slot to the list of slots. */
303 /*===========================================*/
304
305 if (newSlot != NULL)
306 {
307 if (lastSlot == NULL)
308 { slotList = newSlot; }
309 else
310 { lastSlot->next = newSlot; }
311 lastSlot = newSlot;
312 }
313
314 /*================================*/
315 /* Check for closing parenthesis. */
316 /*================================*/
317
318 GetToken(theEnv,readSource,inputToken);
319 if (inputToken->type != RPAREN)
320 {
321 PPBackup(theEnv);
322 SavePPBuffer(theEnv,"\n ");
323 SavePPBuffer(theEnv,inputToken->printForm);
324 }
325 }
326
327 SavePPBuffer(theEnv,"\n");
328
329 /*=======================*/
330 /* Return the slot list. */
331 /*=======================*/
332
333 return(slotList);
334 }
335
336 /*****************************************************/
337 /* ParseSlot: Parses a single slot of a deftemplate. */
338 /*****************************************************/
ParseSlot(void * theEnv,const char * readSource,struct token * inputToken,struct templateSlot * slotList)339 static struct templateSlot *ParseSlot(
340 void *theEnv,
341 const char *readSource,
342 struct token *inputToken,
343 struct templateSlot *slotList)
344 {
345 int parsingMultislot;
346 SYMBOL_HN *slotName;
347 struct templateSlot *newSlot;
348 int rv;
349
350 /*=====================================================*/
351 /* Slots must begin with keyword field or multifield. */
352 /*=====================================================*/
353
354 if ((strcmp(ValueToString(inputToken->value),"field") != 0) &&
355 (strcmp(ValueToString(inputToken->value),"multifield") != 0) &&
356 (strcmp(ValueToString(inputToken->value),"slot") != 0) &&
357 (strcmp(ValueToString(inputToken->value),"multislot") != 0))
358 {
359 SyntaxErrorMessage(theEnv,"deftemplate");
360 DeftemplateData(theEnv)->DeftemplateError = TRUE;
361 return(NULL);
362 }
363
364 /*===============================================*/
365 /* Determine if multifield slot is being parsed. */
366 /*===============================================*/
367
368 if ((strcmp(ValueToString(inputToken->value),"multifield") == 0) ||
369 (strcmp(ValueToString(inputToken->value),"multislot") == 0))
370 { parsingMultislot = TRUE; }
371 else
372 { parsingMultislot = FALSE; }
373
374 /*========================================*/
375 /* The name of the slot must be a symbol. */
376 /*========================================*/
377
378 SavePPBuffer(theEnv," ");
379 GetToken(theEnv,readSource,inputToken);
380 if (inputToken->type != SYMBOL)
381 {
382 SyntaxErrorMessage(theEnv,"deftemplate");
383 DeftemplateData(theEnv)->DeftemplateError = TRUE;
384 return(NULL);
385 }
386
387 slotName = (SYMBOL_HN *) inputToken->value;
388
389 /*================================================*/
390 /* Determine if the slot has already been parsed. */
391 /*================================================*/
392
393 while (slotList != NULL)
394 {
395 if (slotList->slotName == slotName)
396 {
397 AlreadyParsedErrorMessage(theEnv,"slot ",ValueToString(slotList->slotName));
398 DeftemplateData(theEnv)->DeftemplateError = TRUE;
399 return(NULL);
400 }
401
402 slotList = slotList->next;
403 }
404
405 /*===================================*/
406 /* Parse the attributes of the slot. */
407 /*===================================*/
408
409 newSlot = DefinedSlots(theEnv,readSource,slotName,parsingMultislot,inputToken);
410 if (newSlot == NULL)
411 {
412 DeftemplateData(theEnv)->DeftemplateError = TRUE;
413 return(NULL);
414 }
415
416 /*=================================*/
417 /* Check for slot conflict errors. */
418 /*=================================*/
419
420 if (CheckConstraintParseConflicts(theEnv,newSlot->constraints) == FALSE)
421 {
422 ReturnSlots(theEnv,newSlot);
423 DeftemplateData(theEnv)->DeftemplateError = TRUE;
424 return(NULL);
425 }
426
427 if ((newSlot->defaultPresent) || (newSlot->defaultDynamic))
428 { rv = ConstraintCheckExpressionChain(theEnv,newSlot->defaultList,newSlot->constraints); }
429 else
430 { rv = NO_VIOLATION; }
431
432 if ((rv != NO_VIOLATION) && EnvGetStaticConstraintChecking(theEnv))
433 {
434 const char *temp;
435 if (newSlot->defaultDynamic) temp = "the default-dynamic attribute";
436 else temp = "the default attribute";
437 ConstraintViolationErrorMessage(theEnv,"An expression",temp,FALSE,0,
438 newSlot->slotName,0,rv,newSlot->constraints,TRUE);
439 ReturnSlots(theEnv,newSlot);
440 DeftemplateData(theEnv)->DeftemplateError = TRUE;
441 return(NULL);
442 }
443
444 /*==================*/
445 /* Return the slot. */
446 /*==================*/
447
448 return(newSlot);
449 }
450
451 /**************************************************************/
452 /* DefinedSlots: Parses a field or multifield slot attribute. */
453 /**************************************************************/
DefinedSlots(void * theEnv,const char * readSource,SYMBOL_HN * slotName,int multifieldSlot,struct token * inputToken)454 static struct templateSlot *DefinedSlots(
455 void *theEnv,
456 const char *readSource,
457 SYMBOL_HN *slotName,
458 int multifieldSlot,
459 struct token *inputToken)
460 {
461 struct templateSlot *newSlot;
462 struct expr *defaultList;
463 int defaultFound = FALSE;
464 int noneSpecified, deriveSpecified;
465 CONSTRAINT_PARSE_RECORD parsedConstraints;
466
467 /*===========================*/
468 /* Build the slot container. */
469 /*===========================*/
470
471 newSlot = get_struct(theEnv,templateSlot);
472 newSlot->slotName = slotName;
473 newSlot->defaultList = NULL;
474 newSlot->facetList = NULL;
475 newSlot->constraints = GetConstraintRecord(theEnv);
476 if (multifieldSlot)
477 { newSlot->constraints->multifieldsAllowed = TRUE; }
478 newSlot->multislot = multifieldSlot;
479 newSlot->noDefault = FALSE;
480 newSlot->defaultPresent = FALSE;
481 newSlot->defaultDynamic = FALSE;
482 newSlot->next = NULL;
483
484 /*========================================*/
485 /* Parse the primitive slot if it exists. */
486 /*========================================*/
487
488 InitializeConstraintParseRecord(&parsedConstraints);
489 GetToken(theEnv,readSource,inputToken);
490
491 while (inputToken->type != RPAREN)
492 {
493 PPBackup(theEnv);
494 SavePPBuffer(theEnv," ");
495 SavePPBuffer(theEnv,inputToken->printForm);
496
497 /*================================================*/
498 /* Slot attributes begin with a left parenthesis. */
499 /*================================================*/
500
501 if (inputToken->type != LPAREN)
502 {
503 SyntaxErrorMessage(theEnv,"deftemplate");
504 ReturnSlots(theEnv,newSlot);
505 DeftemplateData(theEnv)->DeftemplateError = TRUE;
506 return(NULL);
507 }
508
509 /*=============================================*/
510 /* The name of the attribute must be a symbol. */
511 /*=============================================*/
512
513 GetToken(theEnv,readSource,inputToken);
514 if (inputToken->type != SYMBOL)
515 {
516 SyntaxErrorMessage(theEnv,"deftemplate");
517 ReturnSlots(theEnv,newSlot);
518 DeftemplateData(theEnv)->DeftemplateError = TRUE;
519 return(NULL);
520 }
521
522 /*================================================================*/
523 /* Determine if the attribute is one of the standard constraints. */
524 /*================================================================*/
525
526 if (StandardConstraint(ValueToString(inputToken->value)))
527 {
528 if (ParseStandardConstraint(theEnv,readSource,(ValueToString(inputToken->value)),
529 newSlot->constraints,&parsedConstraints,
530 multifieldSlot) == FALSE)
531 {
532 DeftemplateData(theEnv)->DeftemplateError = TRUE;
533 ReturnSlots(theEnv,newSlot);
534 return(NULL);
535 }
536 }
537
538 /*=================================================*/
539 /* else if the attribute is the default attribute, */
540 /* then get the default list for this slot. */
541 /*=================================================*/
542
543 else if ((strcmp(ValueToString(inputToken->value),"default") == 0) ||
544 (strcmp(ValueToString(inputToken->value),"default-dynamic") == 0))
545 {
546 /*======================================================*/
547 /* Check to see if the default has already been parsed. */
548 /*======================================================*/
549
550 if (defaultFound)
551 {
552 AlreadyParsedErrorMessage(theEnv,"default attribute",NULL);
553 DeftemplateData(theEnv)->DeftemplateError = TRUE;
554 ReturnSlots(theEnv,newSlot);
555 return(NULL);
556 }
557
558 newSlot->noDefault = FALSE;
559
560 /*=====================================================*/
561 /* Determine whether the default is dynamic or static. */
562 /*=====================================================*/
563
564 if (strcmp(ValueToString(inputToken->value),"default") == 0)
565 {
566 newSlot->defaultPresent = TRUE;
567 newSlot->defaultDynamic = FALSE;
568 }
569 else
570 {
571 newSlot->defaultPresent = FALSE;
572 newSlot->defaultDynamic = TRUE;
573 }
574
575 /*===================================*/
576 /* Parse the list of default values. */
577 /*===================================*/
578
579 defaultList = ParseDefault(theEnv,readSource,multifieldSlot,(int) newSlot->defaultDynamic,
580 TRUE,&noneSpecified,&deriveSpecified,&DeftemplateData(theEnv)->DeftemplateError);
581 if (DeftemplateData(theEnv)->DeftemplateError == TRUE)
582 {
583 ReturnSlots(theEnv,newSlot);
584 return(NULL);
585 }
586
587 /*==================================*/
588 /* Store the default with the slot. */
589 /*==================================*/
590
591 defaultFound = TRUE;
592 if (deriveSpecified) newSlot->defaultPresent = FALSE;
593 else if (noneSpecified)
594 {
595 newSlot->noDefault = TRUE;
596 newSlot->defaultPresent = FALSE;
597 }
598 newSlot->defaultList = defaultList;
599 }
600
601 /*===============================================*/
602 /* else if the attribute is the facet attribute. */
603 /*===============================================*/
604
605 else if (strcmp(ValueToString(inputToken->value),"facet") == 0)
606 {
607 if (! ParseFacetAttribute(theEnv,readSource,newSlot,FALSE))
608 {
609 ReturnSlots(theEnv,newSlot);
610 DeftemplateData(theEnv)->DeftemplateError = TRUE;
611 return(NULL);
612 }
613 }
614
615 else if (strcmp(ValueToString(inputToken->value),"multifacet") == 0)
616 {
617 if (! ParseFacetAttribute(theEnv,readSource,newSlot,TRUE))
618 {
619 ReturnSlots(theEnv,newSlot);
620 DeftemplateData(theEnv)->DeftemplateError = TRUE;
621 return(NULL);
622 }
623 }
624
625 /*============================================*/
626 /* Otherwise the attribute is an invalid one. */
627 /*============================================*/
628
629 else
630 {
631 SyntaxErrorMessage(theEnv,"slot attributes");
632 ReturnSlots(theEnv,newSlot);
633 DeftemplateData(theEnv)->DeftemplateError = TRUE;
634 return(NULL);
635 }
636
637 /*===================================*/
638 /* Begin parsing the next attribute. */
639 /*===================================*/
640
641 GetToken(theEnv,readSource,inputToken);
642 }
643
644 /*============================*/
645 /* Return the attribute list. */
646 /*============================*/
647
648 return(newSlot);
649 }
650
651 /***************************************************/
652 /* ParseFacetAttribute: Parses the type attribute. */
653 /***************************************************/
ParseFacetAttribute(void * theEnv,const char * readSource,struct templateSlot * theSlot,intBool multifacet)654 static intBool ParseFacetAttribute(
655 void *theEnv,
656 const char *readSource,
657 struct templateSlot *theSlot,
658 intBool multifacet)
659 {
660 struct token inputToken;
661 SYMBOL_HN *facetName;
662 struct expr *facetPair, *tempFacet, *facetValue = NULL, *lastValue = NULL;
663
664 /*==============================*/
665 /* Parse the name of the facet. */
666 /*==============================*/
667
668 SavePPBuffer(theEnv," ");
669 GetToken(theEnv,readSource,&inputToken);
670
671 /*==================================*/
672 /* The facet name must be a symbol. */
673 /*==================================*/
674
675 if (inputToken.type != SYMBOL)
676 {
677 if (multifacet) SyntaxErrorMessage(theEnv,"multifacet attribute");
678 else SyntaxErrorMessage(theEnv,"facet attribute");
679 return(FALSE);
680 }
681
682 facetName = (SYMBOL_HN *) inputToken.value;
683
684 /*===================================*/
685 /* Don't allow facets with the same */
686 /* name as a predefined CLIPS facet. */
687 /*===================================*/
688
689 /*====================================*/
690 /* Has the facet already been parsed? */
691 /*====================================*/
692
693 for (tempFacet = theSlot->facetList;
694 tempFacet != NULL;
695 tempFacet = tempFacet->nextArg)
696 {
697 if (tempFacet->value == facetName)
698 {
699 if (multifacet) AlreadyParsedErrorMessage(theEnv,"multifacet ",ValueToString(facetName));
700 else AlreadyParsedErrorMessage(theEnv,"facet ",ValueToString(facetName));
701 return(FALSE);
702 }
703 }
704
705 /*===============================*/
706 /* Parse the value of the facet. */
707 /*===============================*/
708
709 SavePPBuffer(theEnv," ");
710 GetToken(theEnv,readSource,&inputToken);
711
712 while (inputToken.type != RPAREN)
713 {
714 /*=====================================*/
715 /* The facet value must be a constant. */
716 /*=====================================*/
717
718 if (! ConstantType(inputToken.type))
719 {
720 if (multifacet) SyntaxErrorMessage(theEnv,"multifacet attribute");
721 else SyntaxErrorMessage(theEnv,"facet attribute");
722 ReturnExpression(theEnv,facetValue);
723 return(FALSE);
724 }
725
726 /*======================================*/
727 /* Add the value to the list of values. */
728 /*======================================*/
729
730 if (lastValue == NULL)
731 {
732 facetValue = GenConstant(theEnv,inputToken.type,inputToken.value);
733 lastValue = facetValue;
734 }
735 else
736 {
737 lastValue->nextArg = GenConstant(theEnv,inputToken.type,inputToken.value);
738 lastValue = lastValue->nextArg;
739 }
740
741 /*=====================*/
742 /* Get the next token. */
743 /*=====================*/
744
745 SavePPBuffer(theEnv," ");
746 GetToken(theEnv,readSource,&inputToken);
747
748 /*===============================================*/
749 /* A facet can't contain more than one constant. */
750 /*===============================================*/
751
752 if ((! multifacet) && (inputToken.type != RPAREN))
753 {
754 SyntaxErrorMessage(theEnv,"facet attribute");
755 ReturnExpression(theEnv,facetValue);
756 return(FALSE);
757 }
758 }
759
760 /*========================================================*/
761 /* Remove the space before the closing right parenthesis. */
762 /*========================================================*/
763
764 PPBackup(theEnv);
765 PPBackup(theEnv);
766 SavePPBuffer(theEnv,")");
767
768 /*====================================*/
769 /* A facet must contain one constant. */
770 /*====================================*/
771
772 if ((! multifacet) && (facetValue == NULL))
773 {
774 SyntaxErrorMessage(theEnv,"facet attribute");
775 return(FALSE);
776 }
777
778 /*=================================================*/
779 /* Add the facet to the list of the slot's facets. */
780 /*=================================================*/
781
782 facetPair = GenConstant(theEnv,SYMBOL,facetName);
783
784 if (multifacet)
785 {
786 facetPair->argList = GenConstant(theEnv,FCALL,(void *) FindFunction(theEnv,"create$"));
787 facetPair->argList->argList = facetValue;
788 }
789 else
790 { facetPair->argList = facetValue; }
791
792 facetPair->nextArg = theSlot->facetList;
793 theSlot->facetList = facetPair;
794
795 /*===============================================*/
796 /* The facet/multifacet was successfully parsed. */
797 /*===============================================*/
798
799 return(TRUE);
800 }
801
802 #endif /* (! RUN_TIME) && (! BLOAD_ONLY) */
803
804 #endif /* DEFTEMPLATE_CONSTRUCT */
805
806
807