clipsruby 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/clipsruby/agenda.c +1373 -0
- data/ext/clipsruby/agenda.h +169 -0
- data/ext/clipsruby/analysis.c +1142 -0
- data/ext/clipsruby/analysis.h +61 -0
- data/ext/clipsruby/argacces.c +526 -0
- data/ext/clipsruby/argacces.h +77 -0
- data/ext/clipsruby/bload.c +884 -0
- data/ext/clipsruby/bload.h +94 -0
- data/ext/clipsruby/bmathfun.c +557 -0
- data/ext/clipsruby/bmathfun.h +66 -0
- data/ext/clipsruby/bsave.c +634 -0
- data/ext/clipsruby/bsave.h +130 -0
- data/ext/clipsruby/classcom.c +976 -0
- data/ext/clipsruby/classcom.h +115 -0
- data/ext/clipsruby/classexm.c +1376 -0
- data/ext/clipsruby/classexm.h +97 -0
- data/ext/clipsruby/classfun.c +1392 -0
- data/ext/clipsruby/classfun.h +164 -0
- data/ext/clipsruby/classinf.c +1245 -0
- data/ext/clipsruby/classinf.h +94 -0
- data/ext/clipsruby/classini.c +843 -0
- data/ext/clipsruby/classini.h +75 -0
- data/ext/clipsruby/classpsr.c +957 -0
- data/ext/clipsruby/classpsr.h +73 -0
- data/ext/clipsruby/clips.h +133 -0
- data/ext/clipsruby/clipsruby.c +619 -0
- data/ext/clipsruby/clsltpsr.c +931 -0
- data/ext/clipsruby/clsltpsr.h +72 -0
- data/ext/clipsruby/commline.c +1217 -0
- data/ext/clipsruby/commline.h +131 -0
- data/ext/clipsruby/conscomp.c +1593 -0
- data/ext/clipsruby/conscomp.h +150 -0
- data/ext/clipsruby/constant.h +264 -0
- data/ext/clipsruby/constrct.c +1090 -0
- data/ext/clipsruby/constrct.h +216 -0
- data/ext/clipsruby/constrnt.c +554 -0
- data/ext/clipsruby/constrnt.h +132 -0
- data/ext/clipsruby/crstrtgy.c +1088 -0
- data/ext/clipsruby/crstrtgy.h +85 -0
- data/ext/clipsruby/cstrcbin.c +185 -0
- data/ext/clipsruby/cstrcbin.h +61 -0
- data/ext/clipsruby/cstrccmp.h +43 -0
- data/ext/clipsruby/cstrccom.c +1791 -0
- data/ext/clipsruby/cstrccom.h +115 -0
- data/ext/clipsruby/cstrcpsr.c +835 -0
- data/ext/clipsruby/cstrcpsr.h +97 -0
- data/ext/clipsruby/cstrnbin.c +282 -0
- data/ext/clipsruby/cstrnbin.h +55 -0
- data/ext/clipsruby/cstrnchk.c +826 -0
- data/ext/clipsruby/cstrnchk.h +91 -0
- data/ext/clipsruby/cstrncmp.c +238 -0
- data/ext/clipsruby/cstrncmp.h +57 -0
- data/ext/clipsruby/cstrnops.c +1176 -0
- data/ext/clipsruby/cstrnops.h +47 -0
- data/ext/clipsruby/cstrnpsr.c +1394 -0
- data/ext/clipsruby/cstrnpsr.h +88 -0
- data/ext/clipsruby/cstrnutl.c +564 -0
- data/ext/clipsruby/cstrnutl.h +54 -0
- data/ext/clipsruby/default.c +454 -0
- data/ext/clipsruby/default.h +57 -0
- data/ext/clipsruby/defins.c +971 -0
- data/ext/clipsruby/defins.h +127 -0
- data/ext/clipsruby/developr.c +677 -0
- data/ext/clipsruby/developr.h +69 -0
- data/ext/clipsruby/dffctbin.c +477 -0
- data/ext/clipsruby/dffctbin.h +76 -0
- data/ext/clipsruby/dffctbsc.c +308 -0
- data/ext/clipsruby/dffctbsc.h +72 -0
- data/ext/clipsruby/dffctcmp.c +297 -0
- data/ext/clipsruby/dffctcmp.h +44 -0
- data/ext/clipsruby/dffctdef.c +364 -0
- data/ext/clipsruby/dffctdef.h +104 -0
- data/ext/clipsruby/dffctpsr.c +179 -0
- data/ext/clipsruby/dffctpsr.h +49 -0
- data/ext/clipsruby/dffnxbin.c +520 -0
- data/ext/clipsruby/dffnxbin.h +67 -0
- data/ext/clipsruby/dffnxcmp.c +378 -0
- data/ext/clipsruby/dffnxcmp.h +54 -0
- data/ext/clipsruby/dffnxexe.c +241 -0
- data/ext/clipsruby/dffnxexe.h +58 -0
- data/ext/clipsruby/dffnxfun.c +1192 -0
- data/ext/clipsruby/dffnxfun.h +155 -0
- data/ext/clipsruby/dffnxpsr.c +514 -0
- data/ext/clipsruby/dffnxpsr.h +57 -0
- data/ext/clipsruby/dfinsbin.c +509 -0
- data/ext/clipsruby/dfinsbin.h +66 -0
- data/ext/clipsruby/dfinscmp.c +345 -0
- data/ext/clipsruby/dfinscmp.h +48 -0
- data/ext/clipsruby/drive.c +1191 -0
- data/ext/clipsruby/drive.h +65 -0
- data/ext/clipsruby/emathfun.c +1213 -0
- data/ext/clipsruby/emathfun.h +99 -0
- data/ext/clipsruby/engine.c +1568 -0
- data/ext/clipsruby/engine.h +203 -0
- data/ext/clipsruby/entities.h +276 -0
- data/ext/clipsruby/envrnbld.c +514 -0
- data/ext/clipsruby/envrnbld.h +40 -0
- data/ext/clipsruby/envrnmnt.c +257 -0
- data/ext/clipsruby/envrnmnt.h +112 -0
- data/ext/clipsruby/evaluatn.c +1736 -0
- data/ext/clipsruby/evaluatn.h +211 -0
- data/ext/clipsruby/expressn.c +494 -0
- data/ext/clipsruby/expressn.h +154 -0
- data/ext/clipsruby/exprnbin.c +538 -0
- data/ext/clipsruby/exprnbin.h +60 -0
- data/ext/clipsruby/exprnops.c +564 -0
- data/ext/clipsruby/exprnops.h +67 -0
- data/ext/clipsruby/exprnpsr.c +1112 -0
- data/ext/clipsruby/exprnpsr.h +98 -0
- data/ext/clipsruby/extconf.rb +2 -0
- data/ext/clipsruby/extnfunc.c +1015 -0
- data/ext/clipsruby/extnfunc.h +157 -0
- data/ext/clipsruby/factbin.c +447 -0
- data/ext/clipsruby/factbin.h +56 -0
- data/ext/clipsruby/factbld.c +1035 -0
- data/ext/clipsruby/factbld.h +63 -0
- data/ext/clipsruby/factcmp.c +386 -0
- data/ext/clipsruby/factcmp.h +46 -0
- data/ext/clipsruby/factcom.c +759 -0
- data/ext/clipsruby/factcom.h +80 -0
- data/ext/clipsruby/factfile.c +1761 -0
- data/ext/clipsruby/factfile.h +54 -0
- data/ext/clipsruby/factfun.c +682 -0
- data/ext/clipsruby/factfun.h +77 -0
- data/ext/clipsruby/factgen.c +1305 -0
- data/ext/clipsruby/factgen.h +229 -0
- data/ext/clipsruby/facthsh.c +438 -0
- data/ext/clipsruby/facthsh.h +81 -0
- data/ext/clipsruby/factlhs.c +250 -0
- data/ext/clipsruby/factlhs.h +54 -0
- data/ext/clipsruby/factmch.c +905 -0
- data/ext/clipsruby/factmch.h +68 -0
- data/ext/clipsruby/factmngr.c +3373 -0
- data/ext/clipsruby/factmngr.h +325 -0
- data/ext/clipsruby/factprt.c +498 -0
- data/ext/clipsruby/factprt.h +60 -0
- data/ext/clipsruby/factqpsr.c +796 -0
- data/ext/clipsruby/factqpsr.h +61 -0
- data/ext/clipsruby/factqury.c +1267 -0
- data/ext/clipsruby/factqury.h +112 -0
- data/ext/clipsruby/factrete.c +978 -0
- data/ext/clipsruby/factrete.h +70 -0
- data/ext/clipsruby/factrhs.c +667 -0
- data/ext/clipsruby/factrhs.h +55 -0
- data/ext/clipsruby/filecom.c +353 -0
- data/ext/clipsruby/filecom.h +137 -0
- data/ext/clipsruby/filertr.c +481 -0
- data/ext/clipsruby/filertr.h +94 -0
- data/ext/clipsruby/fileutil.c +1020 -0
- data/ext/clipsruby/fileutil.h +50 -0
- data/ext/clipsruby/generate.c +1079 -0
- data/ext/clipsruby/generate.h +57 -0
- data/ext/clipsruby/genrcbin.c +902 -0
- data/ext/clipsruby/genrcbin.h +69 -0
- data/ext/clipsruby/genrccmp.c +640 -0
- data/ext/clipsruby/genrccmp.h +59 -0
- data/ext/clipsruby/genrccom.c +2017 -0
- data/ext/clipsruby/genrccom.h +119 -0
- data/ext/clipsruby/genrcexe.c +737 -0
- data/ext/clipsruby/genrcexe.h +73 -0
- data/ext/clipsruby/genrcfun.c +890 -0
- data/ext/clipsruby/genrcfun.h +185 -0
- data/ext/clipsruby/genrcpsr.c +1618 -0
- data/ext/clipsruby/genrcpsr.h +80 -0
- data/ext/clipsruby/globlbin.c +458 -0
- data/ext/clipsruby/globlbin.h +71 -0
- data/ext/clipsruby/globlbsc.c +361 -0
- data/ext/clipsruby/globlbsc.h +83 -0
- data/ext/clipsruby/globlcmp.c +330 -0
- data/ext/clipsruby/globlcmp.h +52 -0
- data/ext/clipsruby/globlcom.c +289 -0
- data/ext/clipsruby/globlcom.h +63 -0
- data/ext/clipsruby/globldef.c +1087 -0
- data/ext/clipsruby/globldef.h +151 -0
- data/ext/clipsruby/globlpsr.c +530 -0
- data/ext/clipsruby/globlpsr.h +59 -0
- data/ext/clipsruby/immthpsr.c +431 -0
- data/ext/clipsruby/immthpsr.h +55 -0
- data/ext/clipsruby/incrrset.c +530 -0
- data/ext/clipsruby/incrrset.h +73 -0
- data/ext/clipsruby/inherpsr.c +850 -0
- data/ext/clipsruby/inherpsr.h +52 -0
- data/ext/clipsruby/inscom.c +2076 -0
- data/ext/clipsruby/inscom.h +182 -0
- data/ext/clipsruby/insfile.c +1764 -0
- data/ext/clipsruby/insfile.h +96 -0
- data/ext/clipsruby/insfun.c +1451 -0
- data/ext/clipsruby/insfun.h +134 -0
- data/ext/clipsruby/insmngr.c +2550 -0
- data/ext/clipsruby/insmngr.h +125 -0
- data/ext/clipsruby/insmoddp.c +1041 -0
- data/ext/clipsruby/insmoddp.h +91 -0
- data/ext/clipsruby/insmult.c +804 -0
- data/ext/clipsruby/insmult.h +62 -0
- data/ext/clipsruby/inspsr.c +602 -0
- data/ext/clipsruby/inspsr.h +60 -0
- data/ext/clipsruby/insquery.c +1278 -0
- data/ext/clipsruby/insquery.h +115 -0
- data/ext/clipsruby/insqypsr.c +729 -0
- data/ext/clipsruby/insqypsr.h +63 -0
- data/ext/clipsruby/iofun.c +2045 -0
- data/ext/clipsruby/iofun.h +116 -0
- data/ext/clipsruby/lgcldpnd.c +644 -0
- data/ext/clipsruby/lgcldpnd.h +75 -0
- data/ext/clipsruby/main.c +112 -0
- data/ext/clipsruby/match.h +142 -0
- data/ext/clipsruby/memalloc.c +481 -0
- data/ext/clipsruby/memalloc.h +197 -0
- data/ext/clipsruby/miscfun.c +1801 -0
- data/ext/clipsruby/miscfun.h +132 -0
- data/ext/clipsruby/modulbin.c +607 -0
- data/ext/clipsruby/modulbin.h +84 -0
- data/ext/clipsruby/modulbsc.c +347 -0
- data/ext/clipsruby/modulbsc.h +67 -0
- data/ext/clipsruby/modulcmp.c +499 -0
- data/ext/clipsruby/modulcmp.h +54 -0
- data/ext/clipsruby/moduldef.c +817 -0
- data/ext/clipsruby/moduldef.h +271 -0
- data/ext/clipsruby/modulpsr.c +1150 -0
- data/ext/clipsruby/modulpsr.h +69 -0
- data/ext/clipsruby/modulutl.c +1036 -0
- data/ext/clipsruby/modulutl.h +84 -0
- data/ext/clipsruby/msgcom.c +1221 -0
- data/ext/clipsruby/msgcom.h +125 -0
- data/ext/clipsruby/msgfun.c +1076 -0
- data/ext/clipsruby/msgfun.h +118 -0
- data/ext/clipsruby/msgpass.c +1441 -0
- data/ext/clipsruby/msgpass.h +103 -0
- data/ext/clipsruby/msgpsr.c +698 -0
- data/ext/clipsruby/msgpsr.h +73 -0
- data/ext/clipsruby/multifld.c +1404 -0
- data/ext/clipsruby/multifld.h +130 -0
- data/ext/clipsruby/multifun.c +2182 -0
- data/ext/clipsruby/multifun.h +102 -0
- data/ext/clipsruby/network.h +142 -0
- data/ext/clipsruby/objbin.c +1522 -0
- data/ext/clipsruby/objbin.h +79 -0
- data/ext/clipsruby/objcmp.c +1507 -0
- data/ext/clipsruby/objcmp.h +71 -0
- data/ext/clipsruby/object.h +260 -0
- data/ext/clipsruby/objrtbin.c +701 -0
- data/ext/clipsruby/objrtbin.h +79 -0
- data/ext/clipsruby/objrtbld.c +2393 -0
- data/ext/clipsruby/objrtbld.h +66 -0
- data/ext/clipsruby/objrtcmp.c +734 -0
- data/ext/clipsruby/objrtcmp.h +66 -0
- data/ext/clipsruby/objrtfnx.c +1330 -0
- data/ext/clipsruby/objrtfnx.h +222 -0
- data/ext/clipsruby/objrtgen.c +736 -0
- data/ext/clipsruby/objrtgen.h +63 -0
- data/ext/clipsruby/objrtmch.c +1524 -0
- data/ext/clipsruby/objrtmch.h +160 -0
- data/ext/clipsruby/parsefun.c +415 -0
- data/ext/clipsruby/parsefun.h +67 -0
- data/ext/clipsruby/pattern.c +1265 -0
- data/ext/clipsruby/pattern.h +163 -0
- data/ext/clipsruby/pprint.c +328 -0
- data/ext/clipsruby/pprint.h +79 -0
- data/ext/clipsruby/prccode.c +1478 -0
- data/ext/clipsruby/prccode.h +145 -0
- data/ext/clipsruby/prcdrfun.c +640 -0
- data/ext/clipsruby/prcdrfun.h +95 -0
- data/ext/clipsruby/prcdrpsr.c +1068 -0
- data/ext/clipsruby/prcdrpsr.h +79 -0
- data/ext/clipsruby/prdctfun.c +869 -0
- data/ext/clipsruby/prdctfun.h +77 -0
- data/ext/clipsruby/prntutil.c +878 -0
- data/ext/clipsruby/prntutil.h +125 -0
- data/ext/clipsruby/proflfun.c +827 -0
- data/ext/clipsruby/proflfun.h +118 -0
- data/ext/clipsruby/reorder.c +2082 -0
- data/ext/clipsruby/reorder.h +172 -0
- data/ext/clipsruby/reteutil.c +1732 -0
- data/ext/clipsruby/reteutil.h +111 -0
- data/ext/clipsruby/retract.c +710 -0
- data/ext/clipsruby/retract.h +74 -0
- data/ext/clipsruby/router.c +737 -0
- data/ext/clipsruby/router.h +147 -0
- data/ext/clipsruby/rulebin.c +1136 -0
- data/ext/clipsruby/rulebin.h +153 -0
- data/ext/clipsruby/rulebld.c +1328 -0
- data/ext/clipsruby/rulebld.h +62 -0
- data/ext/clipsruby/rulebsc.c +517 -0
- data/ext/clipsruby/rulebsc.h +91 -0
- data/ext/clipsruby/rulecmp.c +733 -0
- data/ext/clipsruby/rulecmp.h +63 -0
- data/ext/clipsruby/rulecom.c +1583 -0
- data/ext/clipsruby/rulecom.h +116 -0
- data/ext/clipsruby/rulecstr.c +892 -0
- data/ext/clipsruby/rulecstr.h +53 -0
- data/ext/clipsruby/ruledef.c +559 -0
- data/ext/clipsruby/ruledef.h +179 -0
- data/ext/clipsruby/ruledlt.c +599 -0
- data/ext/clipsruby/ruledlt.h +58 -0
- data/ext/clipsruby/rulelhs.c +1216 -0
- data/ext/clipsruby/rulelhs.h +52 -0
- data/ext/clipsruby/rulepsr.c +1073 -0
- data/ext/clipsruby/rulepsr.h +61 -0
- data/ext/clipsruby/scanner.c +856 -0
- data/ext/clipsruby/scanner.h +112 -0
- data/ext/clipsruby/setup.h +488 -0
- data/ext/clipsruby/sortfun.c +433 -0
- data/ext/clipsruby/sortfun.h +55 -0
- data/ext/clipsruby/strngfun.c +1173 -0
- data/ext/clipsruby/strngfun.h +96 -0
- data/ext/clipsruby/strngrtr.c +523 -0
- data/ext/clipsruby/strngrtr.h +97 -0
- data/ext/clipsruby/symblbin.c +648 -0
- data/ext/clipsruby/symblbin.h +64 -0
- data/ext/clipsruby/symblcmp.c +893 -0
- data/ext/clipsruby/symblcmp.h +61 -0
- data/ext/clipsruby/symbol.c +1961 -0
- data/ext/clipsruby/symbol.h +243 -0
- data/ext/clipsruby/sysdep.c +894 -0
- data/ext/clipsruby/sysdep.h +164 -0
- data/ext/clipsruby/textpro.c +1388 -0
- data/ext/clipsruby/textpro.h +77 -0
- data/ext/clipsruby/tmpltbin.c +609 -0
- data/ext/clipsruby/tmpltbin.h +108 -0
- data/ext/clipsruby/tmpltbsc.c +327 -0
- data/ext/clipsruby/tmpltbsc.h +87 -0
- data/ext/clipsruby/tmpltcmp.c +450 -0
- data/ext/clipsruby/tmpltcmp.h +57 -0
- data/ext/clipsruby/tmpltdef.c +584 -0
- data/ext/clipsruby/tmpltdef.h +155 -0
- data/ext/clipsruby/tmpltfun.c +2477 -0
- data/ext/clipsruby/tmpltfun.h +122 -0
- data/ext/clipsruby/tmpltlhs.c +379 -0
- data/ext/clipsruby/tmpltlhs.h +50 -0
- data/ext/clipsruby/tmpltpsr.c +819 -0
- data/ext/clipsruby/tmpltpsr.h +59 -0
- data/ext/clipsruby/tmpltrhs.c +595 -0
- data/ext/clipsruby/tmpltrhs.h +55 -0
- data/ext/clipsruby/tmpltutl.c +637 -0
- data/ext/clipsruby/tmpltutl.h +82 -0
- data/ext/clipsruby/userdata.c +156 -0
- data/ext/clipsruby/userdata.h +72 -0
- data/ext/clipsruby/userfunctions.c +70 -0
- data/ext/clipsruby/usrsetup.h +7 -0
- data/ext/clipsruby/utility.c +1594 -0
- data/ext/clipsruby/utility.h +250 -0
- data/ext/clipsruby/watch.c +865 -0
- data/ext/clipsruby/watch.h +124 -0
- data/lib/clipsruby.rb +1 -0
- metadata +388 -0
@@ -0,0 +1,1265 @@
|
|
1
|
+
/*******************************************************/
|
2
|
+
/* "C" Language Integrated Production System */
|
3
|
+
/* */
|
4
|
+
/* CLIPS Version 6.40 07/30/16 */
|
5
|
+
/* */
|
6
|
+
/* RULE PATTERN MODULE */
|
7
|
+
/*******************************************************/
|
8
|
+
|
9
|
+
/*************************************************************/
|
10
|
+
/* Purpose: Provides the mechanism for recognizing and */
|
11
|
+
/* parsing the various types of patterns that can be used */
|
12
|
+
/* in the LHS of a rule. In version 6.0, the only pattern */
|
13
|
+
/* types provided are for deftemplate and instance */
|
14
|
+
/* patterns. */
|
15
|
+
/* */
|
16
|
+
/* Principal Programmer(s): */
|
17
|
+
/* Gary D. Riley */
|
18
|
+
/* */
|
19
|
+
/* Contributing Programmer(s): */
|
20
|
+
/* */
|
21
|
+
/* Revision History: */
|
22
|
+
/* */
|
23
|
+
/* 6.24: Renamed BOOLEAN macro type to intBool. */
|
24
|
+
/* */
|
25
|
+
/* 6.30: Added support for hashed alpha memories. */
|
26
|
+
/* */
|
27
|
+
/* Added const qualifiers to remove C++ */
|
28
|
+
/* deprecation warnings. */
|
29
|
+
/* */
|
30
|
+
/* 6.40: Pragma once and other inclusion changes. */
|
31
|
+
/* */
|
32
|
+
/* Added support for booleans with <stdbool.h>. */
|
33
|
+
/* */
|
34
|
+
/* Removed use of void pointers for specific */
|
35
|
+
/* data structures. */
|
36
|
+
/* */
|
37
|
+
/*************************************************************/
|
38
|
+
|
39
|
+
#include "setup.h"
|
40
|
+
|
41
|
+
#include <stdio.h>
|
42
|
+
#include <stdlib.h>
|
43
|
+
|
44
|
+
#if DEFRULE_CONSTRUCT
|
45
|
+
|
46
|
+
#include "constant.h"
|
47
|
+
#include "constrnt.h"
|
48
|
+
#include "cstrnchk.h"
|
49
|
+
#include "cstrnutl.h"
|
50
|
+
#include "envrnmnt.h"
|
51
|
+
#include "exprnpsr.h"
|
52
|
+
#include "match.h"
|
53
|
+
#include "memalloc.h"
|
54
|
+
#include "pprint.h"
|
55
|
+
#include "prntutil.h"
|
56
|
+
#include "reteutil.h"
|
57
|
+
#include "router.h"
|
58
|
+
#include "rulecmp.h"
|
59
|
+
|
60
|
+
#include "pattern.h"
|
61
|
+
|
62
|
+
/***************************************/
|
63
|
+
/* LOCAL INTERNAL FUNCTION DEFINITIONS */
|
64
|
+
/***************************************/
|
65
|
+
|
66
|
+
#if (! RUN_TIME) && (! BLOAD_ONLY)
|
67
|
+
static struct lhsParseNode *ConjuctiveRestrictionParse(Environment *,const char *,struct token *,bool *);
|
68
|
+
static struct lhsParseNode *LiteralRestrictionParse(Environment *,const char *,struct token *,bool *);
|
69
|
+
static bool CheckForVariableMixing(Environment *,struct lhsParseNode *);
|
70
|
+
static void TallyFieldTypes(struct lhsParseNode *);
|
71
|
+
#endif
|
72
|
+
static void DeallocatePatternData(Environment *);
|
73
|
+
static struct patternNodeHashEntry **CreatePatternHashTable(Environment *,unsigned long);
|
74
|
+
|
75
|
+
/*****************************************************************************/
|
76
|
+
/* InitializePatterns: Initializes the global data associated with patterns. */
|
77
|
+
/*****************************************************************************/
|
78
|
+
void InitializePatterns(
|
79
|
+
Environment *theEnv)
|
80
|
+
{
|
81
|
+
AllocateEnvironmentData(theEnv,PATTERN_DATA,sizeof(struct patternData),DeallocatePatternData);
|
82
|
+
PatternData(theEnv)->NextPosition = 1;
|
83
|
+
PatternData(theEnv)->PatternHashTable = CreatePatternHashTable(theEnv,SIZE_PATTERN_HASH);
|
84
|
+
PatternData(theEnv)->PatternHashTableSize = SIZE_PATTERN_HASH;
|
85
|
+
}
|
86
|
+
|
87
|
+
/*******************************************************************/
|
88
|
+
/* CreatePatternHashTable: Creates and initializes a fact hash table. */
|
89
|
+
/*******************************************************************/
|
90
|
+
static struct patternNodeHashEntry **CreatePatternHashTable(
|
91
|
+
Environment *theEnv,
|
92
|
+
unsigned long tableSize)
|
93
|
+
{
|
94
|
+
unsigned long i;
|
95
|
+
struct patternNodeHashEntry **theTable;
|
96
|
+
|
97
|
+
theTable = (struct patternNodeHashEntry **)
|
98
|
+
gm2(theEnv,sizeof (struct patternNodeHashEntry *) * tableSize);
|
99
|
+
|
100
|
+
if (theTable == NULL) ExitRouter(theEnv,EXIT_FAILURE);
|
101
|
+
|
102
|
+
for (i = 0; i < tableSize; i++) theTable[i] = NULL;
|
103
|
+
|
104
|
+
return(theTable);
|
105
|
+
}
|
106
|
+
|
107
|
+
/**************************************************/
|
108
|
+
/* DeallocatePatternData: Deallocates environment */
|
109
|
+
/* data for rule pattern registration. */
|
110
|
+
/**************************************************/
|
111
|
+
static void DeallocatePatternData(
|
112
|
+
Environment *theEnv)
|
113
|
+
{
|
114
|
+
struct reservedSymbol *tmpRSPtr, *nextRSPtr;
|
115
|
+
struct patternParser *tmpPPPtr, *nextPPPtr;
|
116
|
+
struct patternNodeHashEntry *tmpPNEPtr, *nextPNEPtr;
|
117
|
+
unsigned long i;
|
118
|
+
|
119
|
+
tmpRSPtr = PatternData(theEnv)->ListOfReservedPatternSymbols;
|
120
|
+
while (tmpRSPtr != NULL)
|
121
|
+
{
|
122
|
+
nextRSPtr = tmpRSPtr->next;
|
123
|
+
rtn_struct(theEnv,reservedSymbol,tmpRSPtr);
|
124
|
+
tmpRSPtr = nextRSPtr;
|
125
|
+
}
|
126
|
+
|
127
|
+
tmpPPPtr = PatternData(theEnv)->ListOfPatternParsers;
|
128
|
+
while (tmpPPPtr != NULL)
|
129
|
+
{
|
130
|
+
nextPPPtr = tmpPPPtr->next;
|
131
|
+
rtn_struct(theEnv,patternParser,tmpPPPtr);
|
132
|
+
tmpPPPtr = nextPPPtr;
|
133
|
+
}
|
134
|
+
|
135
|
+
for (i = 0; i < PatternData(theEnv)->PatternHashTableSize; i++)
|
136
|
+
{
|
137
|
+
tmpPNEPtr = PatternData(theEnv)->PatternHashTable[i];
|
138
|
+
|
139
|
+
while (tmpPNEPtr != NULL)
|
140
|
+
{
|
141
|
+
nextPNEPtr = tmpPNEPtr->next;
|
142
|
+
rtn_struct(theEnv,patternNodeHashEntry,tmpPNEPtr);
|
143
|
+
tmpPNEPtr = nextPNEPtr;
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
rm(theEnv,PatternData(theEnv)->PatternHashTable,
|
148
|
+
sizeof(struct patternNodeHashEntry *) * PatternData(theEnv)->PatternHashTableSize);
|
149
|
+
}
|
150
|
+
|
151
|
+
/******************************************************************************/
|
152
|
+
/* AddHashedPatternNode: Adds a pattern node entry to the pattern hash table. */
|
153
|
+
/******************************************************************************/
|
154
|
+
void AddHashedPatternNode(
|
155
|
+
Environment *theEnv,
|
156
|
+
void *parent,
|
157
|
+
void *child,
|
158
|
+
unsigned short keyType,
|
159
|
+
void *keyValue)
|
160
|
+
{
|
161
|
+
size_t hashValue;
|
162
|
+
struct patternNodeHashEntry *newhash, *temp;
|
163
|
+
|
164
|
+
hashValue = GetAtomicHashValue(keyType,keyValue,1) + HashExternalAddress(parent,0); /* TBD mult * 30 */
|
165
|
+
|
166
|
+
newhash = get_struct(theEnv,patternNodeHashEntry);
|
167
|
+
newhash->parent = parent;
|
168
|
+
newhash->child = child;
|
169
|
+
newhash->type = keyType;
|
170
|
+
newhash->value = keyValue;
|
171
|
+
|
172
|
+
hashValue = (hashValue % PatternData(theEnv)->PatternHashTableSize);
|
173
|
+
|
174
|
+
temp = PatternData(theEnv)->PatternHashTable[hashValue];
|
175
|
+
PatternData(theEnv)->PatternHashTable[hashValue] = newhash;
|
176
|
+
newhash->next = temp;
|
177
|
+
}
|
178
|
+
|
179
|
+
/***************************************************/
|
180
|
+
/* RemoveHashedPatternNode: Removes a pattern node */
|
181
|
+
/* entry from the pattern node hash table. */
|
182
|
+
/***************************************************/
|
183
|
+
bool RemoveHashedPatternNode(
|
184
|
+
Environment *theEnv,
|
185
|
+
void *parent,
|
186
|
+
void *child,
|
187
|
+
unsigned short keyType,
|
188
|
+
void *keyValue)
|
189
|
+
{
|
190
|
+
size_t hashValue;
|
191
|
+
struct patternNodeHashEntry *hptr, *prev;
|
192
|
+
|
193
|
+
hashValue = GetAtomicHashValue(keyType,keyValue,1) + HashExternalAddress(parent,0); /* TBD mult * 30 */
|
194
|
+
hashValue = (hashValue % PatternData(theEnv)->PatternHashTableSize);
|
195
|
+
|
196
|
+
for (hptr = PatternData(theEnv)->PatternHashTable[hashValue], prev = NULL;
|
197
|
+
hptr != NULL;
|
198
|
+
hptr = hptr->next)
|
199
|
+
{
|
200
|
+
if (hptr->child == child)
|
201
|
+
{
|
202
|
+
if (prev == NULL)
|
203
|
+
{
|
204
|
+
PatternData(theEnv)->PatternHashTable[hashValue] = hptr->next;
|
205
|
+
rtn_struct(theEnv,patternNodeHashEntry,hptr);
|
206
|
+
return true;
|
207
|
+
}
|
208
|
+
else
|
209
|
+
{
|
210
|
+
prev->next = hptr->next;
|
211
|
+
rtn_struct(theEnv,patternNodeHashEntry,hptr);
|
212
|
+
return true;
|
213
|
+
}
|
214
|
+
}
|
215
|
+
prev = hptr;
|
216
|
+
}
|
217
|
+
|
218
|
+
return false;
|
219
|
+
}
|
220
|
+
|
221
|
+
/***********************************************/
|
222
|
+
/* FindHashedPatternNode: Finds a pattern node */
|
223
|
+
/* entry in the pattern node hash table. */
|
224
|
+
/***********************************************/
|
225
|
+
void *FindHashedPatternNode(
|
226
|
+
Environment *theEnv,
|
227
|
+
void *parent,
|
228
|
+
unsigned short keyType,
|
229
|
+
void *keyValue)
|
230
|
+
{
|
231
|
+
size_t hashValue;
|
232
|
+
struct patternNodeHashEntry *hptr;
|
233
|
+
|
234
|
+
hashValue = GetAtomicHashValue(keyType,keyValue,1) + HashExternalAddress(parent,0); /* TBD mult * 30 */
|
235
|
+
hashValue = (hashValue % PatternData(theEnv)->PatternHashTableSize);
|
236
|
+
|
237
|
+
for (hptr = PatternData(theEnv)->PatternHashTable[hashValue];
|
238
|
+
hptr != NULL;
|
239
|
+
hptr = hptr->next)
|
240
|
+
{
|
241
|
+
if ((hptr->parent == parent) &&
|
242
|
+
(keyType == hptr->type) &&
|
243
|
+
(keyValue == hptr->value))
|
244
|
+
{ return(hptr->child); }
|
245
|
+
}
|
246
|
+
|
247
|
+
return NULL;
|
248
|
+
}
|
249
|
+
|
250
|
+
/******************************************************************/
|
251
|
+
/* AddReservedPatternSymbol: Adds a symbol to the list of symbols */
|
252
|
+
/* that are restricted for use in patterns. For example, the */
|
253
|
+
/* deftemplate construct cannot use the symbol "object", since */
|
254
|
+
/* this needs to be reserved for object patterns. Some symbols, */
|
255
|
+
/* such as "exists" are completely reserved and can not be used */
|
256
|
+
/* to start any type of pattern CE. */
|
257
|
+
/******************************************************************/
|
258
|
+
void AddReservedPatternSymbol(
|
259
|
+
Environment *theEnv,
|
260
|
+
const char *theSymbol,
|
261
|
+
const char *reservedBy)
|
262
|
+
{
|
263
|
+
struct reservedSymbol *newSymbol;
|
264
|
+
|
265
|
+
newSymbol = get_struct(theEnv,reservedSymbol);
|
266
|
+
newSymbol->theSymbol = theSymbol;
|
267
|
+
newSymbol->reservedBy = reservedBy;
|
268
|
+
newSymbol->next = PatternData(theEnv)->ListOfReservedPatternSymbols;
|
269
|
+
PatternData(theEnv)->ListOfReservedPatternSymbols = newSymbol;
|
270
|
+
}
|
271
|
+
|
272
|
+
/******************************************************************/
|
273
|
+
/* ReservedPatternSymbol: Returns true if the specified symbol is */
|
274
|
+
/* a reserved pattern symbol, otherwise false is returned. If */
|
275
|
+
/* the construct which is trying to use the symbol is the same */
|
276
|
+
/* construct that reserved the symbol, then false is returned. */
|
277
|
+
/******************************************************************/
|
278
|
+
bool ReservedPatternSymbol(
|
279
|
+
Environment *theEnv,
|
280
|
+
const char *theSymbol,
|
281
|
+
const char *checkedBy)
|
282
|
+
{
|
283
|
+
struct reservedSymbol *currentSymbol;
|
284
|
+
|
285
|
+
for (currentSymbol = PatternData(theEnv)->ListOfReservedPatternSymbols;
|
286
|
+
currentSymbol != NULL;
|
287
|
+
currentSymbol = currentSymbol->next)
|
288
|
+
{
|
289
|
+
if (strcmp(theSymbol,currentSymbol->theSymbol) == 0)
|
290
|
+
{
|
291
|
+
if ((currentSymbol->reservedBy == NULL) || (checkedBy == NULL))
|
292
|
+
{ return true; }
|
293
|
+
|
294
|
+
if (strcmp(checkedBy,currentSymbol->reservedBy) == 0) return false;
|
295
|
+
|
296
|
+
return true;
|
297
|
+
}
|
298
|
+
}
|
299
|
+
|
300
|
+
return false;
|
301
|
+
}
|
302
|
+
|
303
|
+
/********************************************************/
|
304
|
+
/* ReservedPatternSymbolErrorMsg: Generic error message */
|
305
|
+
/* for attempting to use a reserved pattern symbol. */
|
306
|
+
/********************************************************/
|
307
|
+
void ReservedPatternSymbolErrorMsg(
|
308
|
+
Environment *theEnv,
|
309
|
+
const char *theSymbol,
|
310
|
+
const char *usedFor)
|
311
|
+
{
|
312
|
+
PrintErrorID(theEnv,"PATTERN",1,true);
|
313
|
+
WriteString(theEnv,STDERR,"The symbol '");
|
314
|
+
WriteString(theEnv,STDERR,theSymbol);
|
315
|
+
WriteString(theEnv,STDERR,"' has special meaning ");
|
316
|
+
WriteString(theEnv,STDERR,"and may not be used as ");
|
317
|
+
WriteString(theEnv,STDERR,usedFor);
|
318
|
+
WriteString(theEnv,STDERR,".\n");
|
319
|
+
}
|
320
|
+
|
321
|
+
/************************************************************/
|
322
|
+
/* GetNextEntity: Utility routine for accessing all of the */
|
323
|
+
/* data entities that can match patterns. Currently facts */
|
324
|
+
/* and instances are the only data entities available. */
|
325
|
+
/************************************************************/
|
326
|
+
void GetNextPatternEntity(
|
327
|
+
Environment *theEnv,
|
328
|
+
struct patternParser **theParser,
|
329
|
+
struct patternEntity **theEntity)
|
330
|
+
{
|
331
|
+
|
332
|
+
/*=============================================================*/
|
333
|
+
/* If the current parser is NULL, then we want to retrieve the */
|
334
|
+
/* very first data entity. The traversal of entities is done */
|
335
|
+
/* by entity type (e.g. all facts are traversed followed by */
|
336
|
+
/* all instances). To get the first entity type to traverse, */
|
337
|
+
/* the current parser is set to the first parser on the list */
|
338
|
+
/* of pattern parsers. */
|
339
|
+
/*=============================================================*/
|
340
|
+
|
341
|
+
if (*theParser == NULL)
|
342
|
+
{
|
343
|
+
*theParser = PatternData(theEnv)->ListOfPatternParsers;
|
344
|
+
*theEntity = NULL;
|
345
|
+
}
|
346
|
+
|
347
|
+
/*================================================================*/
|
348
|
+
/* Otherwise try to retrieve the next entity following the entity */
|
349
|
+
/* returned by the last call to GetNextEntity. If that entity was */
|
350
|
+
/* the last of its data type, then move on to the next pattern */
|
351
|
+
/* parser, otherwise return that entity as the next one. */
|
352
|
+
/*================================================================*/
|
353
|
+
|
354
|
+
else if (theEntity != NULL)
|
355
|
+
{
|
356
|
+
*theEntity = (struct patternEntity *)
|
357
|
+
(*(*theParser)->entityType->base.getNextFunction)(theEnv,*theEntity);
|
358
|
+
|
359
|
+
if ((*theEntity) != NULL) return;
|
360
|
+
|
361
|
+
*theParser = (*theParser)->next;
|
362
|
+
}
|
363
|
+
|
364
|
+
/*===============================================================*/
|
365
|
+
/* Otherwise, we encountered a situation which should not occur. */
|
366
|
+
/* Once a NULL entity is returned from GetNextEntity, it should */
|
367
|
+
/* not be passed back to GetNextEntity. */
|
368
|
+
/*===============================================================*/
|
369
|
+
|
370
|
+
else
|
371
|
+
{
|
372
|
+
SystemError(theEnv,"PATTERN",1);
|
373
|
+
ExitRouter(theEnv,EXIT_FAILURE);
|
374
|
+
}
|
375
|
+
|
376
|
+
/*================================================*/
|
377
|
+
/* Keep looping through the lists of entities and */
|
378
|
+
/* pattern parsers until an entity is found. */
|
379
|
+
/*================================================*/
|
380
|
+
|
381
|
+
while ((*theEntity == NULL) && (*theParser != NULL))
|
382
|
+
{
|
383
|
+
*theEntity = (struct patternEntity *)
|
384
|
+
(*(*theParser)->entityType->base.getNextFunction)(theEnv,*theEntity);
|
385
|
+
|
386
|
+
if (*theEntity != NULL) return;
|
387
|
+
|
388
|
+
*theParser = (*theParser)->next;
|
389
|
+
}
|
390
|
+
|
391
|
+
return;
|
392
|
+
}
|
393
|
+
|
394
|
+
/**************************************************************/
|
395
|
+
/* DetachPattern: Detaches a pattern from the pattern network */
|
396
|
+
/* by calling the appropriate function for the data type */
|
397
|
+
/* associated with the pattern. */
|
398
|
+
/**************************************************************/
|
399
|
+
void DetachPattern(
|
400
|
+
Environment *theEnv,
|
401
|
+
unsigned short rhsType,
|
402
|
+
struct patternNodeHeader *theHeader)
|
403
|
+
{
|
404
|
+
if (rhsType == 0) return;
|
405
|
+
|
406
|
+
if (PatternData(theEnv)->PatternParserArray[rhsType-1] != NULL)
|
407
|
+
{
|
408
|
+
FlushAlphaMemory(theEnv,theHeader);
|
409
|
+
(*PatternData(theEnv)->PatternParserArray[rhsType-1]->removePatternFunction)(theEnv,theHeader);
|
410
|
+
}
|
411
|
+
}
|
412
|
+
|
413
|
+
/**************************************************/
|
414
|
+
/* AddPatternParser: Adds a pattern type to the */
|
415
|
+
/* list of pattern parsers used to detect valid */
|
416
|
+
/* patterns in the LHS of a rule. */
|
417
|
+
/**************************************************/
|
418
|
+
bool AddPatternParser(
|
419
|
+
Environment *theEnv,
|
420
|
+
struct patternParser *newPtr)
|
421
|
+
{
|
422
|
+
struct patternParser *currentPtr, *lastPtr = NULL;
|
423
|
+
|
424
|
+
/*============================================*/
|
425
|
+
/* Check to see that the limit for the number */
|
426
|
+
/* of pattern parsers has not been exceeded. */
|
427
|
+
/*============================================*/
|
428
|
+
|
429
|
+
if (PatternData(theEnv)->NextPosition >= MAX_POSITIONS) return false;
|
430
|
+
|
431
|
+
/*================================*/
|
432
|
+
/* Create the new pattern parser. */
|
433
|
+
/*================================*/
|
434
|
+
|
435
|
+
newPtr->positionInArray = PatternData(theEnv)->NextPosition;
|
436
|
+
PatternData(theEnv)->PatternParserArray[PatternData(theEnv)->NextPosition-1] = newPtr;
|
437
|
+
PatternData(theEnv)->NextPosition++;
|
438
|
+
|
439
|
+
/*================================*/
|
440
|
+
/* Add the parser to the list of */
|
441
|
+
/* parsers based on its priority. */
|
442
|
+
/*================================*/
|
443
|
+
|
444
|
+
if (PatternData(theEnv)->ListOfPatternParsers == NULL)
|
445
|
+
{
|
446
|
+
newPtr->next = NULL;
|
447
|
+
PatternData(theEnv)->ListOfPatternParsers = newPtr;
|
448
|
+
return true;
|
449
|
+
}
|
450
|
+
|
451
|
+
currentPtr = PatternData(theEnv)->ListOfPatternParsers;
|
452
|
+
while ((currentPtr != NULL) ? (newPtr->priority < currentPtr->priority) : false)
|
453
|
+
{
|
454
|
+
lastPtr = currentPtr;
|
455
|
+
currentPtr = currentPtr->next;
|
456
|
+
}
|
457
|
+
|
458
|
+
if (lastPtr == NULL)
|
459
|
+
{
|
460
|
+
newPtr->next = PatternData(theEnv)->ListOfPatternParsers;
|
461
|
+
PatternData(theEnv)->ListOfPatternParsers = newPtr;
|
462
|
+
}
|
463
|
+
else
|
464
|
+
{
|
465
|
+
newPtr->next = currentPtr;
|
466
|
+
lastPtr->next = newPtr;
|
467
|
+
}
|
468
|
+
|
469
|
+
return true;
|
470
|
+
}
|
471
|
+
|
472
|
+
/****************************************************/
|
473
|
+
/* FindPatternParser: Searches for a pattern parser */
|
474
|
+
/* that can parse a pattern beginning with the */
|
475
|
+
/* specified keyword (e.g. "object"). */
|
476
|
+
/****************************************************/
|
477
|
+
struct patternParser *FindPatternParser(
|
478
|
+
Environment *theEnv,
|
479
|
+
const char *name)
|
480
|
+
{
|
481
|
+
struct patternParser *tempParser;
|
482
|
+
|
483
|
+
for (tempParser = PatternData(theEnv)->ListOfPatternParsers;
|
484
|
+
tempParser != NULL;
|
485
|
+
tempParser = tempParser->next)
|
486
|
+
{ if (strcmp(tempParser->name,name) == 0) return(tempParser); }
|
487
|
+
|
488
|
+
return NULL;
|
489
|
+
}
|
490
|
+
|
491
|
+
/******************************************************/
|
492
|
+
/* GetPatternParser: Returns a pointer to the pattern */
|
493
|
+
/* parser for the specified data entity. */
|
494
|
+
/******************************************************/
|
495
|
+
struct patternParser *GetPatternParser(
|
496
|
+
Environment *theEnv,
|
497
|
+
unsigned short rhsType)
|
498
|
+
{
|
499
|
+
if (rhsType == 0) return NULL;
|
500
|
+
|
501
|
+
return(PatternData(theEnv)->PatternParserArray[rhsType-1]);
|
502
|
+
}
|
503
|
+
|
504
|
+
#if CONSTRUCT_COMPILER && (! RUN_TIME)
|
505
|
+
|
506
|
+
/*************************************************************/
|
507
|
+
/* PatternNodeHeaderToCode: Writes the C code representation */
|
508
|
+
/* of a patternNodeHeader data structure. */
|
509
|
+
/*************************************************************/
|
510
|
+
void PatternNodeHeaderToCode(
|
511
|
+
Environment *theEnv,
|
512
|
+
FILE *fp,
|
513
|
+
struct patternNodeHeader *theHeader,
|
514
|
+
unsigned int imageID,
|
515
|
+
unsigned int maxIndices)
|
516
|
+
{
|
517
|
+
fprintf(fp,"{NULL,NULL,");
|
518
|
+
|
519
|
+
if (theHeader->entryJoin == NULL)
|
520
|
+
{ fprintf(fp,"NULL,"); }
|
521
|
+
else
|
522
|
+
{
|
523
|
+
fprintf(fp,"&%s%u_%lu[%lu],",
|
524
|
+
JoinPrefix(),imageID,
|
525
|
+
(theHeader->entryJoin->bsaveID / maxIndices) + 1,
|
526
|
+
theHeader->entryJoin->bsaveID % maxIndices);
|
527
|
+
}
|
528
|
+
|
529
|
+
PrintHashedExpressionReference(theEnv,fp,theHeader->rightHash,imageID,maxIndices);
|
530
|
+
|
531
|
+
fprintf(fp,",%d,%d,%d,0,0,%d,%d,%d}",theHeader->singlefieldNode,
|
532
|
+
theHeader->multifieldNode,
|
533
|
+
theHeader->stopNode,
|
534
|
+
theHeader->beginSlot,
|
535
|
+
theHeader->endSlot,
|
536
|
+
theHeader->selector);
|
537
|
+
}
|
538
|
+
|
539
|
+
#endif /* CONSTRUCT_COMPILER && (! RUN_TIME) */
|
540
|
+
|
541
|
+
#if (! RUN_TIME) && (! BLOAD_ONLY)
|
542
|
+
|
543
|
+
/****************************************************************/
|
544
|
+
/* PostPatternAnalysis: Calls the post analysis routines for */
|
545
|
+
/* each of the pattern parsers to allow additional processing */
|
546
|
+
/* by the pattern parser after the variable analysis routines */
|
547
|
+
/* have analyzed the LHS patterns. */
|
548
|
+
/****************************************************************/
|
549
|
+
bool PostPatternAnalysis(
|
550
|
+
Environment *theEnv,
|
551
|
+
struct lhsParseNode *theLHS)
|
552
|
+
{
|
553
|
+
struct lhsParseNode *patternPtr;
|
554
|
+
struct patternParser *tempParser;
|
555
|
+
|
556
|
+
for (patternPtr = theLHS; patternPtr != NULL; patternPtr = patternPtr->bottom)
|
557
|
+
{
|
558
|
+
if ((patternPtr->pnType == PATTERN_CE_NODE) && (patternPtr->patternType != NULL))
|
559
|
+
{
|
560
|
+
tempParser = patternPtr->patternType;
|
561
|
+
if (tempParser->postAnalysisFunction != NULL)
|
562
|
+
{ if ((*tempParser->postAnalysisFunction)(theEnv,patternPtr)) return true; }
|
563
|
+
}
|
564
|
+
}
|
565
|
+
|
566
|
+
return false;
|
567
|
+
}
|
568
|
+
|
569
|
+
/******************************************************************/
|
570
|
+
/* RestrictionParse: Parses a single field within a pattern. This */
|
571
|
+
/* field may either be a single field wildcard, a multifield */
|
572
|
+
/* wildcard, a single field variable, a multifield variable, */
|
573
|
+
/* or a series of connected constraints. */
|
574
|
+
/* */
|
575
|
+
/* <constraint> ::= ? | */
|
576
|
+
/* $? | */
|
577
|
+
/* <connected-constraint> */
|
578
|
+
/******************************************************************/
|
579
|
+
struct lhsParseNode *RestrictionParse(
|
580
|
+
Environment *theEnv,
|
581
|
+
const char *readSource,
|
582
|
+
struct token *theToken,
|
583
|
+
bool multifieldSlot,
|
584
|
+
CLIPSLexeme *theSlot,
|
585
|
+
unsigned short slotNumber,
|
586
|
+
CONSTRAINT_RECORD *theConstraints,
|
587
|
+
unsigned short position)
|
588
|
+
{
|
589
|
+
struct lhsParseNode *topNode = NULL, *lastNode = NULL, *nextNode;
|
590
|
+
int numberOfSingleFields = 0;
|
591
|
+
int numberOfMultifields = 0;
|
592
|
+
unsigned short startPosition = position;
|
593
|
+
bool error = false;
|
594
|
+
CONSTRAINT_RECORD *tempConstraints;
|
595
|
+
|
596
|
+
/*==================================================*/
|
597
|
+
/* Keep parsing fields until a right parenthesis is */
|
598
|
+
/* encountered. This will either indicate the end */
|
599
|
+
/* of an instance or deftemplate slot or the end of */
|
600
|
+
/* an ordered fact. */
|
601
|
+
/*==================================================*/
|
602
|
+
|
603
|
+
while (theToken->tknType != RIGHT_PARENTHESIS_TOKEN)
|
604
|
+
{
|
605
|
+
/*========================================*/
|
606
|
+
/* Look for either a single or multifield */
|
607
|
+
/* wildcard or a conjuctive restriction. */
|
608
|
+
/*========================================*/
|
609
|
+
|
610
|
+
if ((theToken->tknType == SF_WILDCARD_TOKEN) ||
|
611
|
+
(theToken->tknType == MF_WILDCARD_TOKEN))
|
612
|
+
{
|
613
|
+
nextNode = GetLHSParseNode(theEnv);
|
614
|
+
if (theToken->tknType == SF_WILDCARD_TOKEN)
|
615
|
+
{ nextNode->pnType = SF_WILDCARD_NODE; }
|
616
|
+
else
|
617
|
+
{ nextNode->pnType = MF_WILDCARD_NODE; }
|
618
|
+
nextNode->negated = false;
|
619
|
+
nextNode->exists = false;
|
620
|
+
GetToken(theEnv,readSource,theToken);
|
621
|
+
}
|
622
|
+
else
|
623
|
+
{
|
624
|
+
nextNode = ConjuctiveRestrictionParse(theEnv,readSource,theToken,&error);
|
625
|
+
if (nextNode == NULL)
|
626
|
+
{
|
627
|
+
ReturnLHSParseNodes(theEnv,topNode);
|
628
|
+
return NULL;
|
629
|
+
}
|
630
|
+
}
|
631
|
+
|
632
|
+
/*========================================================*/
|
633
|
+
/* Fix up the pretty print representation of a multifield */
|
634
|
+
/* slot so that the fields don't run together. */
|
635
|
+
/*========================================================*/
|
636
|
+
|
637
|
+
if ((theToken->tknType != RIGHT_PARENTHESIS_TOKEN) && (multifieldSlot == true))
|
638
|
+
{
|
639
|
+
PPBackup(theEnv);
|
640
|
+
SavePPBuffer(theEnv," ");
|
641
|
+
SavePPBuffer(theEnv,theToken->printForm);
|
642
|
+
}
|
643
|
+
|
644
|
+
/*========================================*/
|
645
|
+
/* Keep track of the number of single and */
|
646
|
+
/* multifield restrictions encountered. */
|
647
|
+
/*========================================*/
|
648
|
+
|
649
|
+
if ((nextNode->pnType == SF_WILDCARD_NODE) ||
|
650
|
+
(nextNode->pnType == SF_VARIABLE_NODE))
|
651
|
+
{ numberOfSingleFields++; }
|
652
|
+
else
|
653
|
+
{ numberOfMultifields++; }
|
654
|
+
|
655
|
+
/*===================================*/
|
656
|
+
/* Assign the slot name and indices. */
|
657
|
+
/*===================================*/
|
658
|
+
|
659
|
+
nextNode->slot = theSlot;
|
660
|
+
nextNode->slotNumber = slotNumber;
|
661
|
+
nextNode->index = position++;
|
662
|
+
|
663
|
+
/*==============================================*/
|
664
|
+
/* If we're not dealing with a multifield slot, */
|
665
|
+
/* attach the constraints directly to the node */
|
666
|
+
/* and return. */
|
667
|
+
/*==============================================*/
|
668
|
+
|
669
|
+
if (! multifieldSlot)
|
670
|
+
{
|
671
|
+
if (theConstraints == NULL)
|
672
|
+
{
|
673
|
+
if (nextNode->pnType == SF_VARIABLE_NODE)
|
674
|
+
{ nextNode->constraints = GetConstraintRecord(theEnv); }
|
675
|
+
else nextNode->constraints = NULL;
|
676
|
+
}
|
677
|
+
else nextNode->constraints = theConstraints;
|
678
|
+
return(nextNode);
|
679
|
+
}
|
680
|
+
|
681
|
+
/*====================================================*/
|
682
|
+
/* Attach the restriction to the list of restrictions */
|
683
|
+
/* already parsed for this slot or ordered fact. */
|
684
|
+
/*====================================================*/
|
685
|
+
|
686
|
+
if (lastNode == NULL) topNode = nextNode;
|
687
|
+
else lastNode->right = nextNode;
|
688
|
+
|
689
|
+
lastNode = nextNode;
|
690
|
+
}
|
691
|
+
|
692
|
+
/*=====================================================*/
|
693
|
+
/* Once we're through parsing, check to make sure that */
|
694
|
+
/* a single field slot was given a restriction. If the */
|
695
|
+
/* following test fails, then we know we're dealing */
|
696
|
+
/* with a multifield slot. */
|
697
|
+
/*=====================================================*/
|
698
|
+
|
699
|
+
if ((topNode == NULL) && (! multifieldSlot))
|
700
|
+
{
|
701
|
+
SyntaxErrorMessage(theEnv,"defrule");
|
702
|
+
return NULL;
|
703
|
+
}
|
704
|
+
|
705
|
+
/*===============================================*/
|
706
|
+
/* Loop through each of the restrictions in the */
|
707
|
+
/* list of restrictions for the multifield slot. */
|
708
|
+
/*===============================================*/
|
709
|
+
|
710
|
+
for (nextNode = topNode; nextNode != NULL; nextNode = nextNode->right)
|
711
|
+
{
|
712
|
+
/*===================================================*/
|
713
|
+
/* Assign a constraint record to each constraint. If */
|
714
|
+
/* the slot has an explicit constraint, then copy */
|
715
|
+
/* this and store it with the constraint. Otherwise, */
|
716
|
+
/* create a constraint record for a single field */
|
717
|
+
/* constraint and skip the constraint modifications */
|
718
|
+
/* for a multifield constraint. */
|
719
|
+
/*===================================================*/
|
720
|
+
|
721
|
+
if (theConstraints == NULL)
|
722
|
+
{
|
723
|
+
if (nextNode->pnType == SF_VARIABLE_NODE)
|
724
|
+
{ nextNode->constraints = GetConstraintRecord(theEnv); }
|
725
|
+
else
|
726
|
+
{ continue; }
|
727
|
+
}
|
728
|
+
else
|
729
|
+
{ nextNode->constraints = CopyConstraintRecord(theEnv,theConstraints); }
|
730
|
+
|
731
|
+
/*==========================================*/
|
732
|
+
/* Remove the min and max field constraints */
|
733
|
+
/* for the entire slot from the constraint */
|
734
|
+
/* record for this single constraint. */
|
735
|
+
/*==========================================*/
|
736
|
+
|
737
|
+
ReturnExpression(theEnv,nextNode->constraints->minFields);
|
738
|
+
ReturnExpression(theEnv,nextNode->constraints->maxFields);
|
739
|
+
nextNode->constraints->minFields = GenConstant(theEnv,SYMBOL_TYPE,SymbolData(theEnv)->NegativeInfinity);
|
740
|
+
nextNode->constraints->maxFields = GenConstant(theEnv,SYMBOL_TYPE,SymbolData(theEnv)->PositiveInfinity);
|
741
|
+
nextNode->derivedConstraints = true;
|
742
|
+
|
743
|
+
/*====================================================*/
|
744
|
+
/* If we're not dealing with a multifield constraint, */
|
745
|
+
/* then no further modifications are needed to the */
|
746
|
+
/* min and max constraints for this constraint. */
|
747
|
+
/*====================================================*/
|
748
|
+
|
749
|
+
if ((nextNode->pnType != MF_WILDCARD_NODE) && (nextNode->pnType != MF_VARIABLE_NODE))
|
750
|
+
{ continue; }
|
751
|
+
|
752
|
+
/*==========================================================*/
|
753
|
+
/* Create a separate constraint record to keep track of the */
|
754
|
+
/* cardinality information for this multifield constraint. */
|
755
|
+
/*==========================================================*/
|
756
|
+
|
757
|
+
tempConstraints = GetConstraintRecord(theEnv);
|
758
|
+
SetConstraintType(MULTIFIELD_TYPE,tempConstraints);
|
759
|
+
tempConstraints->singlefieldsAllowed = false;
|
760
|
+
tempConstraints->multifield = nextNode->constraints;
|
761
|
+
nextNode->constraints = tempConstraints;
|
762
|
+
|
763
|
+
/*=====================================================*/
|
764
|
+
/* Adjust the min and max field values for this single */
|
765
|
+
/* multifield constraint based on the min and max */
|
766
|
+
/* fields for the entire slot and the number of single */
|
767
|
+
/* field values contained in the slot. */
|
768
|
+
/*=====================================================*/
|
769
|
+
|
770
|
+
if (theConstraints->maxFields->value != SymbolData(theEnv)->PositiveInfinity)
|
771
|
+
{
|
772
|
+
ReturnExpression(theEnv,tempConstraints->maxFields);
|
773
|
+
tempConstraints->maxFields = GenConstant(theEnv,INTEGER_TYPE,CreateInteger(theEnv,theConstraints->maxFields->integerValue->contents - numberOfSingleFields));
|
774
|
+
}
|
775
|
+
|
776
|
+
if ((numberOfMultifields == 1) && (theConstraints->minFields->value != SymbolData(theEnv)->NegativeInfinity))
|
777
|
+
{
|
778
|
+
ReturnExpression(theEnv,tempConstraints->minFields);
|
779
|
+
tempConstraints->minFields = GenConstant(theEnv,INTEGER_TYPE,CreateInteger(theEnv,theConstraints->minFields->integerValue->contents - numberOfSingleFields));
|
780
|
+
}
|
781
|
+
}
|
782
|
+
|
783
|
+
/*================================================*/
|
784
|
+
/* If a multifield slot is being parsed, place a */
|
785
|
+
/* node on top of the list of constraints parsed. */
|
786
|
+
/*================================================*/
|
787
|
+
|
788
|
+
if (multifieldSlot)
|
789
|
+
{
|
790
|
+
nextNode = GetLHSParseNode(theEnv);
|
791
|
+
nextNode->pnType = MF_WILDCARD_NODE;
|
792
|
+
nextNode->multifieldSlot = true;
|
793
|
+
nextNode->bottom = topNode;
|
794
|
+
nextNode->slot = theSlot;
|
795
|
+
nextNode->slotNumber = slotNumber;
|
796
|
+
nextNode->index = startPosition;
|
797
|
+
nextNode->constraints = theConstraints;
|
798
|
+
topNode = nextNode;
|
799
|
+
TallyFieldTypes(topNode->bottom);
|
800
|
+
}
|
801
|
+
|
802
|
+
/*=================================*/
|
803
|
+
/* Return the list of constraints. */
|
804
|
+
/*=================================*/
|
805
|
+
|
806
|
+
return(topNode);
|
807
|
+
}
|
808
|
+
|
809
|
+
/***************************************************************/
|
810
|
+
/* TallyFieldTypes: Determines the number of single field and */
|
811
|
+
/* multifield variables and wildcards that appear before and */
|
812
|
+
/* after each restriction found in a multifield slot. */
|
813
|
+
/***************************************************************/
|
814
|
+
static void TallyFieldTypes(
|
815
|
+
struct lhsParseNode *theRestrictions)
|
816
|
+
{
|
817
|
+
struct lhsParseNode *tempNode1, *tempNode2, *tempNode3;
|
818
|
+
unsigned short totalSingleFields = 0, totalMultiFields = 0;
|
819
|
+
unsigned short runningSingleFields = 0, runningMultiFields = 0;
|
820
|
+
|
821
|
+
/*========================================*/
|
822
|
+
/* Compute the total number of single and */
|
823
|
+
/* multifield variables and wildcards. */
|
824
|
+
/*========================================*/
|
825
|
+
|
826
|
+
for (tempNode1 = theRestrictions; tempNode1 != NULL; tempNode1 = tempNode1->right)
|
827
|
+
{
|
828
|
+
if ((tempNode1->pnType == SF_VARIABLE_NODE) || (tempNode1->pnType == SF_WILDCARD_NODE))
|
829
|
+
{ totalSingleFields++; }
|
830
|
+
else
|
831
|
+
{ totalMultiFields++; }
|
832
|
+
}
|
833
|
+
|
834
|
+
/*======================================================*/
|
835
|
+
/* Loop through each constraint tallying the numbers of */
|
836
|
+
/* the variable types before and after along the way. */
|
837
|
+
/*======================================================*/
|
838
|
+
|
839
|
+
for (tempNode1 = theRestrictions; tempNode1 != NULL; tempNode1 = tempNode1->right)
|
840
|
+
{
|
841
|
+
/*===================================*/
|
842
|
+
/* Assign the values to the "binding */
|
843
|
+
/* variable" node of the constraint. */
|
844
|
+
/*===================================*/
|
845
|
+
|
846
|
+
tempNode1->singleFieldsBefore = runningSingleFields;
|
847
|
+
tempNode1->multiFieldsBefore = runningMultiFields;
|
848
|
+
tempNode1->withinMultifieldSlot = true;
|
849
|
+
|
850
|
+
if ((tempNode1->pnType == SF_VARIABLE_NODE) || (tempNode1->pnType == SF_WILDCARD_NODE))
|
851
|
+
{
|
852
|
+
tempNode1->singleFieldsAfter = totalSingleFields - (runningSingleFields + 1);
|
853
|
+
tempNode1->multiFieldsAfter = totalMultiFields - runningMultiFields;
|
854
|
+
}
|
855
|
+
else
|
856
|
+
{
|
857
|
+
tempNode1->singleFieldsAfter = totalSingleFields - runningSingleFields;
|
858
|
+
tempNode1->multiFieldsAfter = totalMultiFields - (runningMultiFields + 1);
|
859
|
+
}
|
860
|
+
|
861
|
+
/*=====================================================*/
|
862
|
+
/* Assign the values to each of the and (&) and or (|) */
|
863
|
+
/* connected constraints within the constraint. */
|
864
|
+
/*=====================================================*/
|
865
|
+
|
866
|
+
for (tempNode2 = tempNode1->bottom; tempNode2 != NULL; tempNode2 = tempNode2->bottom)
|
867
|
+
{
|
868
|
+
for (tempNode3 = tempNode2; tempNode3 != NULL; tempNode3 = tempNode3->right)
|
869
|
+
{
|
870
|
+
tempNode3->singleFieldsBefore = tempNode1->singleFieldsBefore;
|
871
|
+
tempNode3->singleFieldsAfter = tempNode1->singleFieldsAfter;
|
872
|
+
tempNode3->multiFieldsBefore = tempNode1->multiFieldsBefore;
|
873
|
+
tempNode3->multiFieldsAfter = tempNode1->multiFieldsAfter;
|
874
|
+
tempNode3->withinMultifieldSlot = true;
|
875
|
+
}
|
876
|
+
}
|
877
|
+
|
878
|
+
/*=======================================*/
|
879
|
+
/* Calculate the running total of single */
|
880
|
+
/* and multifield constraints. */
|
881
|
+
/*=======================================*/
|
882
|
+
|
883
|
+
if ((tempNode1->pnType == SF_VARIABLE_NODE) || (tempNode1->pnType == SF_WILDCARD_NODE))
|
884
|
+
{ runningSingleFields++; }
|
885
|
+
else
|
886
|
+
{ runningMultiFields++; }
|
887
|
+
}
|
888
|
+
}
|
889
|
+
|
890
|
+
/*******************************************************************/
|
891
|
+
/* ConjuctiveRestrictionParse: Parses a single constraint field in */
|
892
|
+
/* a pattern that is not a single field wildcard, multifield */
|
893
|
+
/* wildcard, or multifield variable. The field may consist of a */
|
894
|
+
/* number of subfields tied together using the & connective */
|
895
|
+
/* constraint and/or the | connective constraint. */
|
896
|
+
/* */
|
897
|
+
/* <connected-constraint> */
|
898
|
+
/* ::= <single-constraint> | */
|
899
|
+
/* <single-constraint> & <connected-constraint> | */
|
900
|
+
/* <single-constraint> | <connected-constraint> */
|
901
|
+
/*******************************************************************/
|
902
|
+
static struct lhsParseNode *ConjuctiveRestrictionParse(
|
903
|
+
Environment *theEnv,
|
904
|
+
const char *readSource,
|
905
|
+
struct token *theToken,
|
906
|
+
bool *error)
|
907
|
+
{
|
908
|
+
struct lhsParseNode *bindNode;
|
909
|
+
struct lhsParseNode *theNode, *nextOr, *nextAnd;
|
910
|
+
TokenType connectorType;
|
911
|
+
|
912
|
+
/*=====================================*/
|
913
|
+
/* Get the first node and determine if */
|
914
|
+
/* it is a binding variable. */
|
915
|
+
/*=====================================*/
|
916
|
+
|
917
|
+
theNode = LiteralRestrictionParse(theEnv,readSource,theToken,error);
|
918
|
+
|
919
|
+
if (*error == true)
|
920
|
+
{ return NULL; }
|
921
|
+
|
922
|
+
GetToken(theEnv,readSource,theToken);
|
923
|
+
|
924
|
+
if (((theNode->pnType == SF_VARIABLE_NODE) || (theNode->pnType == MF_VARIABLE_NODE)) &&
|
925
|
+
(theNode->negated == false) &&
|
926
|
+
(theToken->tknType != OR_CONSTRAINT_TOKEN))
|
927
|
+
{
|
928
|
+
theNode->bindingVariable = true;
|
929
|
+
bindNode = theNode;
|
930
|
+
nextOr = NULL;
|
931
|
+
nextAnd = NULL;
|
932
|
+
}
|
933
|
+
else
|
934
|
+
{
|
935
|
+
bindNode = GetLHSParseNode(theEnv);
|
936
|
+
if (theNode->pnType == MF_VARIABLE_NODE) bindNode->pnType = MF_WILDCARD_NODE;
|
937
|
+
else bindNode->pnType = SF_WILDCARD_NODE;
|
938
|
+
bindNode->negated = false;
|
939
|
+
bindNode->bottom = theNode;
|
940
|
+
nextOr = theNode;
|
941
|
+
nextAnd = theNode;
|
942
|
+
}
|
943
|
+
|
944
|
+
/*===================================*/
|
945
|
+
/* Process the connected constraints */
|
946
|
+
/* within the constraint */
|
947
|
+
/*===================================*/
|
948
|
+
|
949
|
+
while ((theToken->tknType == OR_CONSTRAINT_TOKEN) ||
|
950
|
+
(theToken->tknType == AND_CONSTRAINT_TOKEN))
|
951
|
+
{
|
952
|
+
/*==========================*/
|
953
|
+
/* Get the next constraint. */
|
954
|
+
/*==========================*/
|
955
|
+
|
956
|
+
connectorType = theToken->tknType;
|
957
|
+
|
958
|
+
GetToken(theEnv,readSource,theToken);
|
959
|
+
theNode = LiteralRestrictionParse(theEnv,readSource,theToken,error);
|
960
|
+
|
961
|
+
if (*error == true)
|
962
|
+
{
|
963
|
+
ReturnLHSParseNodes(theEnv,bindNode);
|
964
|
+
return NULL;
|
965
|
+
}
|
966
|
+
|
967
|
+
/*=======================================*/
|
968
|
+
/* Attach the new constraint to the list */
|
969
|
+
/* of constraints for this field. */
|
970
|
+
/*=======================================*/
|
971
|
+
|
972
|
+
if (connectorType == OR_CONSTRAINT_TOKEN)
|
973
|
+
{
|
974
|
+
if (nextOr == NULL)
|
975
|
+
{ bindNode->bottom = theNode; }
|
976
|
+
else
|
977
|
+
{ nextOr->bottom = theNode; }
|
978
|
+
nextOr = theNode;
|
979
|
+
nextAnd = theNode;
|
980
|
+
}
|
981
|
+
else if (connectorType == AND_CONSTRAINT_TOKEN)
|
982
|
+
{
|
983
|
+
if (nextAnd == NULL)
|
984
|
+
{
|
985
|
+
bindNode->bottom = theNode;
|
986
|
+
nextOr = theNode;
|
987
|
+
}
|
988
|
+
else
|
989
|
+
{ nextAnd->right = theNode; }
|
990
|
+
nextAnd = theNode;
|
991
|
+
}
|
992
|
+
else
|
993
|
+
{
|
994
|
+
SystemError(theEnv,"RULEPSR",1);
|
995
|
+
ExitRouter(theEnv,EXIT_FAILURE);
|
996
|
+
}
|
997
|
+
|
998
|
+
/*==================================================*/
|
999
|
+
/* Determine if any more restrictions are connected */
|
1000
|
+
/* to the current list of restrictions. */
|
1001
|
+
/*==================================================*/
|
1002
|
+
|
1003
|
+
GetToken(theEnv,readSource,theToken);
|
1004
|
+
}
|
1005
|
+
|
1006
|
+
/*==========================================*/
|
1007
|
+
/* Check for illegal mixing of single and */
|
1008
|
+
/* multifield values within the constraint. */
|
1009
|
+
/*==========================================*/
|
1010
|
+
|
1011
|
+
if (CheckForVariableMixing(theEnv,bindNode))
|
1012
|
+
{
|
1013
|
+
*error = true;
|
1014
|
+
ReturnLHSParseNodes(theEnv,bindNode);
|
1015
|
+
return NULL;
|
1016
|
+
}
|
1017
|
+
|
1018
|
+
/*========================*/
|
1019
|
+
/* Return the constraint. */
|
1020
|
+
/*========================*/
|
1021
|
+
|
1022
|
+
return(bindNode);
|
1023
|
+
}
|
1024
|
+
|
1025
|
+
/*****************************************************/
|
1026
|
+
/* CheckForVariableMixing: Checks a field constraint */
|
1027
|
+
/* to determine if single and multifield variables */
|
1028
|
+
/* are illegally mixed within it. */
|
1029
|
+
/*****************************************************/
|
1030
|
+
static bool CheckForVariableMixing(
|
1031
|
+
Environment *theEnv,
|
1032
|
+
struct lhsParseNode *theRestriction)
|
1033
|
+
{
|
1034
|
+
struct lhsParseNode *tempRestriction;
|
1035
|
+
CONSTRAINT_RECORD *theConstraint;
|
1036
|
+
bool multifield = false;
|
1037
|
+
bool singlefield = false;
|
1038
|
+
bool constant = false;
|
1039
|
+
bool singleReturnValue = false;
|
1040
|
+
bool multiReturnValue = false;
|
1041
|
+
|
1042
|
+
/*================================================*/
|
1043
|
+
/* If the constraint contains a binding variable, */
|
1044
|
+
/* determine whether it is a single field or */
|
1045
|
+
/* multifield variable. */
|
1046
|
+
/*================================================*/
|
1047
|
+
|
1048
|
+
if (theRestriction->pnType == SF_VARIABLE_NODE) singlefield = true;
|
1049
|
+
else if (theRestriction->pnType == MF_VARIABLE_NODE) multifield = true;
|
1050
|
+
|
1051
|
+
/*===========================================*/
|
1052
|
+
/* Loop through each of the or (|) connected */
|
1053
|
+
/* constraints within the constraint. */
|
1054
|
+
/*===========================================*/
|
1055
|
+
|
1056
|
+
for (theRestriction = theRestriction->bottom;
|
1057
|
+
theRestriction != NULL;
|
1058
|
+
theRestriction = theRestriction->bottom)
|
1059
|
+
{
|
1060
|
+
/*============================================*/
|
1061
|
+
/* Loop through each of the and (&) connected */
|
1062
|
+
/* constraints within the or (|) constraint. */
|
1063
|
+
/*============================================*/
|
1064
|
+
|
1065
|
+
for (tempRestriction = theRestriction;
|
1066
|
+
tempRestriction != NULL;
|
1067
|
+
tempRestriction = tempRestriction->right)
|
1068
|
+
{
|
1069
|
+
/*=====================================================*/
|
1070
|
+
/* Determine if the constraint contains a single field */
|
1071
|
+
/* variable, multifield variable, constant (a single */
|
1072
|
+
/* field), a return value constraint of a function */
|
1073
|
+
/* returning a single field value, or a return value */
|
1074
|
+
/* constraint of a function returning a multifield */
|
1075
|
+
/* value. */
|
1076
|
+
/*=====================================================*/
|
1077
|
+
|
1078
|
+
if (tempRestriction->pnType == SF_VARIABLE_NODE) singlefield = true;
|
1079
|
+
else if (tempRestriction->pnType == MF_VARIABLE_NODE) multifield = true;
|
1080
|
+
else if (ConstantNode(tempRestriction)) constant = true;
|
1081
|
+
else if (tempRestriction->pnType == RETURN_VALUE_CONSTRAINT_NODE)
|
1082
|
+
{
|
1083
|
+
theConstraint = FunctionCallToConstraintRecord(theEnv,tempRestriction->expression->value);
|
1084
|
+
if (theConstraint->anyAllowed) { /* Do nothing. */ }
|
1085
|
+
else if (theConstraint->multifieldsAllowed) multiReturnValue = true;
|
1086
|
+
else singleReturnValue = true;
|
1087
|
+
RemoveConstraint(theEnv,theConstraint);
|
1088
|
+
}
|
1089
|
+
}
|
1090
|
+
}
|
1091
|
+
|
1092
|
+
/*================================================================*/
|
1093
|
+
/* Using a single field value (a single field variable, constant, */
|
1094
|
+
/* or function returning a single field value) together with a */
|
1095
|
+
/* multifield value (a multifield variable or function returning */
|
1096
|
+
/* a multifield value) is illegal. Return true if this occurs. */
|
1097
|
+
/*================================================================*/
|
1098
|
+
|
1099
|
+
if ((singlefield || constant || singleReturnValue) &&
|
1100
|
+
(multifield || multiReturnValue))
|
1101
|
+
|
1102
|
+
{
|
1103
|
+
PrintErrorID(theEnv,"PATTERN",2,true);
|
1104
|
+
WriteString(theEnv,STDERR,"Single and multifield constraints cannot be mixed in a field constraint.\n");
|
1105
|
+
return true;
|
1106
|
+
}
|
1107
|
+
|
1108
|
+
/*=======================================*/
|
1109
|
+
/* Otherwise return false to indicate no */
|
1110
|
+
/* illegal variable mixing was detected. */
|
1111
|
+
/*=======================================*/
|
1112
|
+
|
1113
|
+
return false;
|
1114
|
+
}
|
1115
|
+
|
1116
|
+
/***********************************************************/
|
1117
|
+
/* LiteralRestrictionParse: Parses a single constraint. */
|
1118
|
+
/* The constraint may be a literal constraint, a */
|
1119
|
+
/* predicate constraint, a return value constraint, or a */
|
1120
|
+
/* variable constraint. The constraints may also be */
|
1121
|
+
/* negated using the ~ connective constraint. */
|
1122
|
+
/* */
|
1123
|
+
/* <single-constraint> ::= <term> | ~<term> */
|
1124
|
+
/* */
|
1125
|
+
/* <term> ::= <constant> | */
|
1126
|
+
/* <single-field-variable> | */
|
1127
|
+
/* <multi-field-variable> | */
|
1128
|
+
/* :<function-call> | */
|
1129
|
+
/* =<function-call> */
|
1130
|
+
/***********************************************************/
|
1131
|
+
static struct lhsParseNode *LiteralRestrictionParse(
|
1132
|
+
Environment *theEnv,
|
1133
|
+
const char *readSource,
|
1134
|
+
struct token *theToken,
|
1135
|
+
bool *error)
|
1136
|
+
{
|
1137
|
+
struct lhsParseNode *topNode;
|
1138
|
+
struct expr *theExpression;
|
1139
|
+
|
1140
|
+
/*============================================*/
|
1141
|
+
/* Create a node to represent the constraint. */
|
1142
|
+
/*============================================*/
|
1143
|
+
|
1144
|
+
topNode = GetLHSParseNode(theEnv);
|
1145
|
+
|
1146
|
+
/*=================================================*/
|
1147
|
+
/* Determine if the constraint has a '~' preceding */
|
1148
|
+
/* it. If it does, then the field is negated */
|
1149
|
+
/* (e.g. ~red means "not the constant red." */
|
1150
|
+
/*=================================================*/
|
1151
|
+
|
1152
|
+
if (theToken->tknType == NOT_CONSTRAINT_TOKEN)
|
1153
|
+
{
|
1154
|
+
GetToken(theEnv,readSource,theToken);
|
1155
|
+
topNode->negated = true;
|
1156
|
+
}
|
1157
|
+
else
|
1158
|
+
{ topNode->negated = false; }
|
1159
|
+
|
1160
|
+
/*===========================================*/
|
1161
|
+
/* Determine if the constraint is one of the */
|
1162
|
+
/* recognized types. These are ?variables, */
|
1163
|
+
/* symbols, strings, numbers, :(expression), */
|
1164
|
+
/* and =(expression). */
|
1165
|
+
/*===========================================*/
|
1166
|
+
|
1167
|
+
/*============================================*/
|
1168
|
+
/* Any symbol is valid, but an = signifies a */
|
1169
|
+
/* return value constraint and an : signifies */
|
1170
|
+
/* a predicate constraint. */
|
1171
|
+
/*============================================*/
|
1172
|
+
|
1173
|
+
if (theToken->tknType == SYMBOL_TOKEN)
|
1174
|
+
{
|
1175
|
+
/*==============================*/
|
1176
|
+
/* If the symbol is an =, parse */
|
1177
|
+
/* a return value constraint. */
|
1178
|
+
/*==============================*/
|
1179
|
+
|
1180
|
+
if (strcmp(theToken->lexemeValue->contents,"=") == 0)
|
1181
|
+
{
|
1182
|
+
theExpression = Function0Parse(theEnv,readSource);
|
1183
|
+
if (theExpression == NULL)
|
1184
|
+
{
|
1185
|
+
*error = true;
|
1186
|
+
ReturnLHSParseNodes(theEnv,topNode);
|
1187
|
+
return NULL;
|
1188
|
+
}
|
1189
|
+
topNode->pnType = RETURN_VALUE_CONSTRAINT_NODE;
|
1190
|
+
topNode->expression = ExpressionToLHSParseNodes(theEnv,theExpression);
|
1191
|
+
ReturnExpression(theEnv,theExpression);
|
1192
|
+
}
|
1193
|
+
|
1194
|
+
/*=============================*/
|
1195
|
+
/* If the symbol is a :, parse */
|
1196
|
+
/* a predicate constraint. */
|
1197
|
+
/*=============================*/
|
1198
|
+
|
1199
|
+
else if (strcmp(theToken->lexemeValue->contents,":") == 0)
|
1200
|
+
{
|
1201
|
+
theExpression = Function0Parse(theEnv,readSource);
|
1202
|
+
if (theExpression == NULL)
|
1203
|
+
{
|
1204
|
+
*error = true;
|
1205
|
+
ReturnLHSParseNodes(theEnv,topNode);
|
1206
|
+
return NULL;
|
1207
|
+
}
|
1208
|
+
topNode->pnType = PREDICATE_CONSTRAINT_NODE;
|
1209
|
+
topNode->expression = ExpressionToLHSParseNodes(theEnv,theExpression);
|
1210
|
+
ReturnExpression(theEnv,theExpression);
|
1211
|
+
}
|
1212
|
+
|
1213
|
+
/*==============================================*/
|
1214
|
+
/* Otherwise, treat the constraint as a symbol. */
|
1215
|
+
/*==============================================*/
|
1216
|
+
|
1217
|
+
else
|
1218
|
+
{
|
1219
|
+
topNode->pnType = SYMBOL_NODE;
|
1220
|
+
topNode->value = theToken->value;
|
1221
|
+
}
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
/*=====================================================*/
|
1225
|
+
/* Single and multifield variables and float, integer, */
|
1226
|
+
/* string, and instance name constants are also valid. */
|
1227
|
+
/*=====================================================*/
|
1228
|
+
|
1229
|
+
else if ((theToken->tknType == SF_VARIABLE_TOKEN) ||
|
1230
|
+
(theToken->tknType == MF_VARIABLE_TOKEN) ||
|
1231
|
+
(theToken->tknType == FLOAT_TOKEN) ||
|
1232
|
+
(theToken->tknType == INTEGER_TOKEN) ||
|
1233
|
+
(theToken->tknType == STRING_TOKEN) ||
|
1234
|
+
(theToken->tknType == INSTANCE_NAME_TOKEN))
|
1235
|
+
{
|
1236
|
+
topNode->pnType = TypeToNodeType(TokenTypeToType(theToken->tknType));
|
1237
|
+
topNode->value = theToken->value;
|
1238
|
+
}
|
1239
|
+
|
1240
|
+
/*===========================*/
|
1241
|
+
/* Anything else is invalid. */
|
1242
|
+
/*===========================*/
|
1243
|
+
|
1244
|
+
else
|
1245
|
+
{
|
1246
|
+
SyntaxErrorMessage(theEnv,"defrule");
|
1247
|
+
*error = true;
|
1248
|
+
ReturnLHSParseNodes(theEnv,topNode);
|
1249
|
+
return NULL;
|
1250
|
+
}
|
1251
|
+
|
1252
|
+
/*===============================*/
|
1253
|
+
/* Return the parsed constraint. */
|
1254
|
+
/*===============================*/
|
1255
|
+
|
1256
|
+
return topNode;
|
1257
|
+
}
|
1258
|
+
|
1259
|
+
#endif /* (! RUN_TIME) && (! BLOAD_ONLY) */
|
1260
|
+
|
1261
|
+
#endif /* DEFRULE_CONSTRUCT */
|
1262
|
+
|
1263
|
+
|
1264
|
+
|
1265
|
+
|