1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*             CLIPS Version 6.30  08/16/14            */
5    /*                                                     */
6    /*               PARSING FUNCTIONS MODULE              */
7    /*******************************************************/
8 
9 /*************************************************************/
10 /* Purpose: Contains the code for several parsing related    */
11 /*   functions including...                                  */
12 /*                                                           */
13 /* Principal Programmer(s):                                  */
14 /*      Gary D. Riley                                        */
15 /*                                                           */
16 /* Contributing Programmer(s):                               */
17 /*                                                           */
18 /* Revision History:                                         */
19 /*                                                           */
20 /*      6.23: Correction for FalseSymbol/TrueSymbol. DR0859  */
21 /*                                                           */
22 /*      6.24: Corrected code to remove run-time program      */
23 /*            compiler warnings.                             */
24 /*                                                           */
25 /*      6.30: Changed integer type/precision.                */
26 /*                                                           */
27 /*            Removed conditional code for unsupported       */
28 /*            compilers/operating systems (IBM_MCW,          */
29 /*            MAC_MCW, and IBM_TBC).                         */
30 /*                                                           */
31 /*            Added const qualifiers to remove C++           */
32 /*            deprecation warnings.                          */
33 /*                                                           */
34 /*            Fixed function declaration issue when          */
35 /*            BLOAD_ONLY compiler flag is set to 1.          */
36 /*                                                           */
37 /*************************************************************/
38 
39 #define _PARSEFUN_SOURCE_
40 
41 #include "setup.h"
42 
43 #include <string.h>
44 
45 #include "argacces.h"
46 #include "cstrcpsr.h"
47 #include "envrnmnt.h"
48 #include "exprnpsr.h"
49 #include "extnfunc.h"
50 #include "memalloc.h"
51 #include "multifld.h"
52 #include "prcdrpsr.h"
53 #include "router.h"
54 #include "strngrtr.h"
55 #include "utility.h"
56 
57 #include "parsefun.h"
58 
59 #define PARSEFUN_DATA 11
60 
61 struct parseFunctionData
62   {
63    char *ErrorString;
64    size_t ErrorCurrentPosition;
65    size_t ErrorMaximumPosition;
66    char *WarningString;
67    size_t WarningCurrentPosition;
68    size_t WarningMaximumPosition;
69   };
70 
71 #define ParseFunctionData(theEnv) ((struct parseFunctionData *) GetEnvironmentData(theEnv,PARSEFUN_DATA))
72 
73 /***************************************/
74 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
75 /***************************************/
76 
77 #if (! RUN_TIME) && (! BLOAD_ONLY)
78    static int                     FindErrorCapture(void *,const char *);
79    static int                     PrintErrorCapture(void *,const char *,const char *);
80    static void                    DeactivateErrorCapture(void *);
81    static void                    SetErrorCaptureValues(void *,DATA_OBJECT_PTR);
82 #endif
83 
84 /*****************************************/
85 /* ParseFunctionDefinitions: Initializes */
86 /*   the parsing related functions.      */
87 /*****************************************/
ParseFunctionDefinitions(void * theEnv)88 globle void ParseFunctionDefinitions(
89   void *theEnv)
90   {
91    AllocateEnvironmentData(theEnv,PARSEFUN_DATA,sizeof(struct parseFunctionData),NULL);
92 
93 #if ! RUN_TIME
94    EnvDefineFunction2(theEnv,"check-syntax",'u',PTIEF CheckSyntaxFunction,"CheckSyntaxFunction","11s");
95 #endif
96   }
97 
98 #if (! RUN_TIME) && (! BLOAD_ONLY)
99 /*******************************************/
100 /* CheckSyntaxFunction: H/L access routine */
101 /*   for the check-syntax function.        */
102 /*******************************************/
CheckSyntaxFunction(void * theEnv,DATA_OBJECT * returnValue)103 globle void CheckSyntaxFunction(
104   void *theEnv,
105   DATA_OBJECT *returnValue)
106   {
107    DATA_OBJECT theArg;
108 
109    /*===============================*/
110    /* Set up a default return value */
111    /* (TRUE for problems found).    */
112    /*===============================*/
113 
114    SetpType(returnValue,SYMBOL);
115    SetpValue(returnValue,EnvTrueSymbol(theEnv));
116 
117    /*=====================================================*/
118    /* Function check-syntax expects exactly one argument. */
119    /*=====================================================*/
120 
121    if (EnvArgCountCheck(theEnv,"check-syntax",EXACTLY,1) == -1) return;
122 
123    /*========================================*/
124    /* The argument should be of type STRING. */
125    /*========================================*/
126 
127    if (EnvArgTypeCheck(theEnv,"check-syntax",1,STRING,&theArg) == FALSE)
128      { return; }
129 
130    /*===================*/
131    /* Check the syntax. */
132    /*===================*/
133 
134    CheckSyntax(theEnv,DOToString(theArg),returnValue);
135   }
136 
137 /*********************************/
138 /* CheckSyntax: C access routine */
139 /*   for the build function.     */
140 /*********************************/
CheckSyntax(void * theEnv,const char * theString,DATA_OBJECT_PTR returnValue)141 globle int CheckSyntax(
142   void *theEnv,
143   const char *theString,
144   DATA_OBJECT_PTR returnValue)
145   {
146    const char *name;
147    struct token theToken;
148    struct expr *top;
149    short rv;
150 
151    /*==============================*/
152    /* Set the default return value */
153    /* (TRUE for problems found).   */
154    /*==============================*/
155 
156    SetpType(returnValue,SYMBOL);
157    SetpValue(returnValue,EnvTrueSymbol(theEnv));
158 
159    /*===========================================*/
160    /* Create a string source router so that the */
161    /* string can be used as an input source.    */
162    /*===========================================*/
163 
164    if (OpenStringSource(theEnv,"check-syntax",theString,0) == 0)
165      { return(TRUE); }
166 
167    /*=================================*/
168    /* Only expressions and constructs */
169    /* can have their syntax checked.  */
170    /*=================================*/
171 
172    GetToken(theEnv,"check-syntax",&theToken);
173 
174    if (theToken.type != LPAREN)
175      {
176       CloseStringSource(theEnv,"check-syntax");
177       SetpValue(returnValue,EnvAddSymbol(theEnv,"MISSING-LEFT-PARENTHESIS"));
178       return(TRUE);
179      }
180 
181    /*========================================*/
182    /* The next token should be the construct */
183    /* type or function name.                 */
184    /*========================================*/
185 
186    GetToken(theEnv,"check-syntax",&theToken);
187    if (theToken.type != SYMBOL)
188      {
189       CloseStringSource(theEnv,"check-syntax");
190       SetpValue(returnValue,EnvAddSymbol(theEnv,"EXPECTED-SYMBOL-AFTER-LEFT-PARENTHESIS"));
191       return(TRUE);
192      }
193 
194    name = ValueToString(theToken.value);
195 
196    /*==============================================*/
197    /* Set up a router to capture the error output. */
198    /*==============================================*/
199 
200    EnvAddRouter(theEnv,"error-capture",40,
201               FindErrorCapture, PrintErrorCapture,
202               NULL, NULL, NULL);
203 
204    /*================================*/
205    /* Determine if it's a construct. */
206    /*================================*/
207 
208    if (FindConstruct(theEnv,name))
209      {
210       ConstructData(theEnv)->CheckSyntaxMode = TRUE;
211       rv = (short) ParseConstruct(theEnv,name,"check-syntax");
212       GetToken(theEnv,"check-syntax",&theToken);
213       ConstructData(theEnv)->CheckSyntaxMode = FALSE;
214 
215       if (rv)
216         {
217          EnvPrintRouter(theEnv,WERROR,"\nERROR:\n");
218          PrintInChunks(theEnv,WERROR,GetPPBuffer(theEnv));
219          EnvPrintRouter(theEnv,WERROR,"\n");
220         }
221 
222       DestroyPPBuffer(theEnv);
223 
224       CloseStringSource(theEnv,"check-syntax");
225 
226       if ((rv != FALSE) || (ParseFunctionData(theEnv)->WarningString != NULL))
227         {
228          SetErrorCaptureValues(theEnv,returnValue);
229          DeactivateErrorCapture(theEnv);
230          return(TRUE);
231         }
232 
233       if (theToken.type != STOP)
234         {
235          SetpValue(returnValue,EnvAddSymbol(theEnv,"EXTRANEOUS-INPUT-AFTER-LAST-PARENTHESIS"));
236          DeactivateErrorCapture(theEnv);
237          return(TRUE);
238         }
239 
240       SetpType(returnValue,SYMBOL);
241       SetpValue(returnValue,EnvFalseSymbol(theEnv));
242       DeactivateErrorCapture(theEnv);
243       return(FALSE);
244      }
245 
246    /*=======================*/
247    /* Parse the expression. */
248    /*=======================*/
249 
250    top = Function2Parse(theEnv,"check-syntax",name);
251    GetToken(theEnv,"check-syntax",&theToken);
252    ClearParsedBindNames(theEnv);
253    CloseStringSource(theEnv,"check-syntax");
254 
255    if (top == NULL)
256      {
257       SetErrorCaptureValues(theEnv,returnValue);
258       DeactivateErrorCapture(theEnv);
259       return(TRUE);
260      }
261 
262    if (theToken.type != STOP)
263      {
264       SetpValue(returnValue,EnvAddSymbol(theEnv,"EXTRANEOUS-INPUT-AFTER-LAST-PARENTHESIS"));
265       DeactivateErrorCapture(theEnv);
266       ReturnExpression(theEnv,top);
267       return(TRUE);
268      }
269 
270    DeactivateErrorCapture(theEnv);
271 
272    ReturnExpression(theEnv,top);
273    SetpType(returnValue,SYMBOL);
274    SetpValue(returnValue,EnvFalseSymbol(theEnv));
275    return(FALSE);
276   }
277 
278 /**************************************************/
279 /* DeactivateErrorCapture: Deactivates the error  */
280 /*   capture router and the strings used to store */
281 /*   the captured information.                    */
282 /**************************************************/
DeactivateErrorCapture(void * theEnv)283 static void DeactivateErrorCapture(
284   void *theEnv)
285   {
286    if (ParseFunctionData(theEnv)->ErrorString != NULL)
287      {
288       rm(theEnv,ParseFunctionData(theEnv)->ErrorString,ParseFunctionData(theEnv)->ErrorMaximumPosition);
289       ParseFunctionData(theEnv)->ErrorString = NULL;
290      }
291 
292    if (ParseFunctionData(theEnv)->WarningString != NULL)
293      {
294       rm(theEnv,ParseFunctionData(theEnv)->WarningString,ParseFunctionData(theEnv)->WarningMaximumPosition);
295       ParseFunctionData(theEnv)->WarningString = NULL;
296      }
297 
298    ParseFunctionData(theEnv)->ErrorCurrentPosition = 0;
299    ParseFunctionData(theEnv)->ErrorMaximumPosition = 0;
300    ParseFunctionData(theEnv)->WarningCurrentPosition = 0;
301    ParseFunctionData(theEnv)->WarningMaximumPosition = 0;
302 
303    EnvDeleteRouter(theEnv,"error-capture");
304   }
305 
306 /******************************************************************/
307 /* SetErrorCaptureValues: Stores the error/warnings captured when */
308 /*   parsing an expression or construct into a multifield value.  */
309 /*   The first field contains the output sent to the WERROR       */
310 /*   logical name and the second field contains the output sent   */
311 /*   to the WWARNING logical name. FALSE is stored in either      */
312 /*   position if no output was sent to those logical names.       */
313 /******************************************************************/
SetErrorCaptureValues(void * theEnv,DATA_OBJECT_PTR returnValue)314 static void SetErrorCaptureValues(
315   void *theEnv,
316   DATA_OBJECT_PTR returnValue)
317   {
318    struct multifield *theMultifield;
319 
320    theMultifield = (struct multifield *) EnvCreateMultifield(theEnv,2L);
321 
322    if (ParseFunctionData(theEnv)->ErrorString != NULL)
323      {
324       SetMFType(theMultifield,1,STRING);
325       SetMFValue(theMultifield,1,EnvAddSymbol(theEnv,ParseFunctionData(theEnv)->ErrorString));
326      }
327    else
328      {
329       SetMFType(theMultifield,1,SYMBOL);
330       SetMFValue(theMultifield,1,EnvFalseSymbol(theEnv));
331      }
332 
333    if (ParseFunctionData(theEnv)->WarningString != NULL)
334      {
335       SetMFType(theMultifield,2,STRING);
336       SetMFValue(theMultifield,2,EnvAddSymbol(theEnv,ParseFunctionData(theEnv)->WarningString));
337      }
338    else
339      {
340       SetMFType(theMultifield,2,SYMBOL);
341       SetMFValue(theMultifield,2,EnvFalseSymbol(theEnv));
342      }
343 
344    SetpType(returnValue,MULTIFIELD);
345    SetpDOBegin(returnValue,1);
346    SetpDOEnd(returnValue,2);
347    SetpValue(returnValue,(void *) theMultifield);
348   }
349 
350 /**********************************/
351 /* FindErrorCapture: Find routine */
352 /*   for the check-syntax router. */
353 /**********************************/
FindErrorCapture(void * theEnv,const char * logicalName)354 static int FindErrorCapture(
355   void *theEnv,
356   const char *logicalName)
357   {
358 #if MAC_XCD
359 #pragma unused(theEnv)
360 #endif
361 
362    if ((strcmp(logicalName,WERROR) == 0) ||
363        (strcmp(logicalName,WWARNING) == 0))
364      { return(TRUE); }
365 
366    return(FALSE);
367   }
368 
369 /************************************/
370 /* PrintErrorCapture: Print routine */
371 /*   for the check-syntax router.   */
372 /************************************/
PrintErrorCapture(void * theEnv,const char * logicalName,const char * str)373 static int PrintErrorCapture(
374   void *theEnv,
375   const char *logicalName,
376   const char *str)
377   {
378    if (strcmp(logicalName,WERROR) == 0)
379      {
380       ParseFunctionData(theEnv)->ErrorString = AppendToString(theEnv,str,ParseFunctionData(theEnv)->ErrorString,
381                                    &ParseFunctionData(theEnv)->ErrorCurrentPosition,
382                                    &ParseFunctionData(theEnv)->ErrorMaximumPosition);
383      }
384    else if (strcmp(logicalName,WWARNING) == 0)
385      {
386       ParseFunctionData(theEnv)->WarningString = AppendToString(theEnv,str,ParseFunctionData(theEnv)->WarningString,
387                                      &ParseFunctionData(theEnv)->WarningCurrentPosition,
388                                      &ParseFunctionData(theEnv)->WarningMaximumPosition);
389      }
390 
391    return(1);
392   }
393 
394 #else
395 /****************************************************/
396 /* CheckSyntaxFunction: This is the non-functional  */
397 /*   stub provided for use with a run-time version. */
398 /****************************************************/
CheckSyntaxFunction(void * theEnv,DATA_OBJECT * returnValue)399 globle void CheckSyntaxFunction(
400   void *theEnv,
401   DATA_OBJECT *returnValue)
402   {
403    PrintErrorID(theEnv,"PARSEFUN",1,FALSE);
404    EnvPrintRouter(theEnv,WERROR,"Function check-syntax does not work in run time modules.\n");
405    SetpType(returnValue,SYMBOL);
406    SetpValue(returnValue,EnvTrueSymbol(theEnv));
407   }
408 
409 /************************************************/
410 /* CheckSyntax: This is the non-functional stub */
411 /*   provided for use with a run-time version.  */
412 /************************************************/
CheckSyntax(void * theEnv,const char * theString,DATA_OBJECT_PTR returnValue)413 globle int CheckSyntax(
414   void *theEnv,
415   const char *theString,
416   DATA_OBJECT_PTR returnValue)
417   {
418    PrintErrorID(theEnv,"PARSEFUN",1,FALSE);
419    EnvPrintRouter(theEnv,WERROR,"Function check-syntax does not work in run time modules.\n");
420    SetpType(returnValue,SYMBOL);
421    SetpValue(returnValue,EnvTrueSymbol(theEnv));
422    return(TRUE);
423   }
424 
425 #endif /* (! RUN_TIME) && (! BLOAD_ONLY) */
426 
427 
428