1 /*************************************************************************
2 * *
3 * YAP Prolog *
4 * *
5 * Yap Prolog was developed at NCCUP - Universidade do Porto *
6 * *
7 * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8 * *
9 **************************************************************************
10 * *
11 * File: parser.c *
12 * Last rev: *
13 * mods: *
14 * comments: Prolog's parser *
15 * *
16 *************************************************************************/
17 #ifdef SCCS
18 static char SccsId[] = "%W% %G%";
19 #endif
20 /*
21 * Description:
22 *
23 * parser: produces a prolog term from an array of tokens
24 *
25 * parser usage: the parser takes its input from an array of token descriptions
26 * addressed by the global variable 'tokptr' and produces a Term as result. A
27 * macro 'NextToken' should be defined in 'yap.h' for advancing 'tokptr' from
28 * one token to the next. In the distributed version this macro also updates
29 * a variable named 'toktide' for keeping track of how far the parser went
30 * before failling with a syntax error. The parser should be invoked with
31 * 'tokptr' pointing to the first token. The last token should have type
32 * 'eot_tok'. The parser return either a Term. Syntactic errors are signaled
33 * by a return value 0. The parser builds new terms on the 'global stack' and
34 * also uses an auxiliary stack pointed to by 'AuxSp'. In the distributed
35 * version this auxiliary stack is assumed to grow downwards. This
36 * assumption, however, is only relevant to routine 'ParseArgs', and to the
37 * variable toktide. conclusion: set tokptr pointing to first token set AuxSp
38 * Call Parse
39 *
40 * VSC: Working whithout known bugs in 87/4/6
41 *
42 * LD: -I or +I evaluated by parser 87/4/28
43 *
44 * LD: parser extended 87/4/28
45 *
46 */
47
48
49 #include "Yap.h"
50 #include "Yatom.h"
51 #include "YapHeap.h"
52 #include "yapio.h"
53 #include "eval.h"
54 #if HAVE_STRING_H
55 #include <string.h>
56 #endif
57
58 #ifdef __STDC__XXX
59 #define Volatile volatile
60 #else
61 #define Volatile
62 #endif
63
64
65 /* weak backtraking mechanism based on long_jump */
66
67 typedef struct jmp_buff_struct {
68 sigjmp_buf JmpBuff;
69 } JMPBUFF;
70
71 STATIC_PROTO(void GNextToken, (void));
72 STATIC_PROTO(void checkfor, (Term, JMPBUFF *));
73 STATIC_PROTO(Term ParseArgs, (Atom, JMPBUFF *));
74 STATIC_PROTO(Term ParseList, (JMPBUFF *));
75 STATIC_PROTO(Term ParseTerm, (int, JMPBUFF *));
76
77
78 #define TRY(S,P) \
79 { Volatile JMPBUFF *saveenv, newenv; \
80 Volatile TokEntry *saveT=Yap_tokptr; \
81 Volatile CELL *saveH=H; \
82 Volatile int savecurprio=curprio; \
83 saveenv=FailBuff; \
84 if(!sigsetjmp(newenv.JmpBuff, 0)) { \
85 FailBuff = &newenv; \
86 S; \
87 FailBuff=saveenv; \
88 P; \
89 } \
90 else { FailBuff=saveenv; \
91 H=saveH; \
92 curprio = savecurprio; \
93 Yap_tokptr=saveT; \
94 } \
95 }
96
97 #define TRY3(S,P,F) \
98 { Volatile JMPBUFF *saveenv, newenv; \
99 Volatile TokEntry *saveT=Yap_tokptr; \
100 Volatile CELL *saveH=H; \
101 saveenv=FailBuff; \
102 if(!sigsetjmp(newenv.JmpBuff, 0)) { \
103 FailBuff = &newenv; \
104 S; \
105 FailBuff=saveenv; \
106 P; \
107 } \
108 else { \
109 FailBuff=saveenv; \
110 H=saveH; \
111 Yap_tokptr=saveT; \
112 F } \
113 }
114
115
116 #define FAIL siglongjmp(FailBuff->JmpBuff,1)
117
118 VarEntry *
Yap_LookupVar(char * var)119 Yap_LookupVar(char *var) /* lookup variable in variables table */
120 {
121 VarEntry *p;
122
123 #ifdef DEBUG
124 if (Yap_Option[4])
125 fprintf(Yap_stderr,"[LookupVar %s]", var);
126 #endif
127 if (var[0] != '_' || var[1] != '\0') {
128 VarEntry **op = &Yap_VarTable;
129 unsigned char *vp = (unsigned char *)var;
130 UInt hv;
131
132 p = Yap_VarTable;
133 hv = HashFunction(vp) % AtomHashTableSize;
134 while (p != NULL) {
135 CELL hpv = p->hv;
136 if (hv == hpv) {
137 Int scmp;
138 if ((scmp = strcmp(var, p->VarRep)) == 0) {
139 return(p);
140 } else if (scmp < 0) {
141 op = &(p->VarLeft);
142 p = p->VarLeft;
143 } else {
144 op = &(p->VarRight);
145 p = p->VarRight;
146 }
147 } else if (hv < hpv) {
148 op = &(p->VarLeft);
149 p = p->VarLeft;
150 } else {
151 op = &(p->VarRight);
152 p = p->VarRight;
153 }
154 }
155 p = (VarEntry *) Yap_AllocScannerMemory(strlen(var) + sizeof(VarEntry));
156 *op = p;
157 p->VarLeft = p->VarRight = NULL;
158 p->hv = hv;
159 strcpy(p->VarRep, var);
160 } else {
161 /* anon var */
162 p = (VarEntry *) Yap_AllocScannerMemory(sizeof(VarEntry) + 2);
163 p->VarLeft = Yap_AnonVarTable;
164 Yap_AnonVarTable = p;
165 p->VarRight = NULL;
166 p->hv = 0L;
167 p->VarRep[0] = '_';
168 p->VarRep[1] = '\0';
169 }
170 p->VarAdr = TermNil;
171 return (p);
172 }
173
174 static Term
VarNames(VarEntry * p,Term l)175 VarNames(VarEntry *p,Term l)
176 {
177 if (p != NULL) {
178 if (strcmp(p->VarRep, "_") != 0) {
179 Term o = MkPairTerm(MkPairTerm(Yap_StringToList(p->VarRep), p->VarAdr),
180 VarNames(p->VarRight,
181 VarNames(p->VarLeft,l)));
182 if (H > ASP-4096) {
183 save_machine_regs();
184 siglongjmp(Yap_IOBotch,1);
185 }
186 return(o);
187 } else {
188 return(VarNames(p->VarRight,VarNames(p->VarLeft,l)));
189 }
190 } else {
191 return (l);
192 }
193 }
194
195 Term
Yap_VarNames(VarEntry * p,Term l)196 Yap_VarNames(VarEntry *p,Term l)
197 {
198 return VarNames(p,l);
199 }
200
201 static int
IsPrefixOp(Atom op,int * pptr,int * rpptr)202 IsPrefixOp(Atom op,int *pptr, int *rpptr)
203 {
204 int p;
205
206 OpEntry *opp = Yap_GetOpProp(op, PREFIX_OP);
207 if (!opp)
208 return FALSE;
209 if (opp->OpModule &&
210 opp->OpModule != CurrentModule)
211 return FALSE;
212 if ((p = opp->Prefix) != 0) {
213 READ_UNLOCK(opp->OpRWLock);
214 *pptr = *rpptr = p & MaskPrio;
215 if (p & DcrrpFlag)
216 --* rpptr;
217 return TRUE;
218 } else {
219 READ_UNLOCK(opp->OpRWLock);
220 return FALSE;
221 }
222 }
223
224 int
Yap_IsPrefixOp(Atom op,int * pptr,int * rpptr)225 Yap_IsPrefixOp(Atom op,int *pptr, int *rpptr)
226 {
227 return IsPrefixOp(op,pptr,rpptr);
228 }
229
230 static int
IsInfixOp(Atom op,int * pptr,int * lpptr,int * rpptr)231 IsInfixOp(Atom op, int *pptr, int *lpptr, int *rpptr)
232 {
233 int p;
234
235 OpEntry *opp = Yap_GetOpProp(op, INFIX_OP);
236 if (!opp)
237 return FALSE;
238 if (opp->OpModule &&
239 opp->OpModule != CurrentModule)
240 return FALSE;
241 if ((p = opp->Infix) != 0) {
242 READ_UNLOCK(opp->OpRWLock);
243 *pptr = *rpptr = *lpptr = p & MaskPrio;
244 if (p & DcrrpFlag)
245 --* rpptr;
246 if (p & DcrlpFlag)
247 --* lpptr;
248 return TRUE;
249 } else {
250 READ_UNLOCK(opp->OpRWLock);
251 return FALSE;
252 }
253 }
254
255 int
Yap_IsInfixOp(Atom op,int * pptr,int * lpptr,int * rpptr)256 Yap_IsInfixOp(Atom op, int *pptr, int *lpptr, int *rpptr)
257 {
258 return IsInfixOp(op, pptr, lpptr, rpptr);
259 }
260
261 static int
IsPosfixOp(Atom op,int * pptr,int * lpptr)262 IsPosfixOp(Atom op, int *pptr, int *lpptr)
263 {
264 int p;
265
266 OpEntry *opp = Yap_GetOpProp(op, POSFIX_OP);
267 if (!opp)
268 return FALSE;
269 if (opp->OpModule &&
270 opp->OpModule != CurrentModule)
271 return FALSE;
272 if ((p = opp->Posfix) != 0) {
273 READ_UNLOCK(opp->OpRWLock);
274 *pptr = *lpptr = p & MaskPrio;
275 if (p & DcrlpFlag)
276 --* lpptr;
277 return (TRUE);
278 } else {
279 READ_UNLOCK(opp->OpRWLock);
280 return (FALSE);
281 }
282 }
283
284 int
Yap_IsPosfixOp(Atom op,int * pptr,int * lpptr)285 Yap_IsPosfixOp(Atom op, int *pptr, int *lpptr)
286 {
287 return IsPosfixOp(op, pptr, lpptr);
288 }
289
290 inline static void
GNextToken(void)291 GNextToken(void)
292 {
293 if (Yap_tokptr->Tok == Ord(eot_tok))
294 return;
295 #ifdef EMACS
296 if ((Yap_tokptr = Yap_tokptr->TokNext)->TokPos > Yap_toktide->TokPos)
297 Yap_toktide = Yap_tokptr;
298 #else
299 if (Yap_tokptr == Yap_toktide)
300 Yap_toktide = Yap_tokptr = Yap_tokptr->TokNext;
301 else
302 Yap_tokptr = Yap_tokptr->TokNext;
303 #endif
304 }
305
306 inline static void
checkfor(Term c,JMPBUFF * FailBuff)307 checkfor(Term c, JMPBUFF *FailBuff)
308 {
309 if (Yap_tokptr->Tok != Ord(Ponctuation_tok)
310 || Yap_tokptr->TokInfo != c)
311 FAIL;
312 NextToken;
313 }
314
315 static Term
ParseArgs(Atom a,JMPBUFF * FailBuff)316 ParseArgs(Atom a, JMPBUFF *FailBuff)
317 {
318 int nargs = 0;
319 Term *p, t;
320 Functor func;
321 #ifdef SFUNC
322 SFEntry *pe = (SFEntry *) Yap_GetAProp(a, SFProperty);
323 #endif
324
325 NextToken;
326 p = (Term *) ParserAuxSp;
327 while (1) {
328 Term *tp = (Term *)ParserAuxSp;
329 if (ParserAuxSp+1 > Yap_TrailTop) {
330 Yap_ErrorMessage = "Trail Overflow";
331 FAIL;
332 }
333 *tp++ = Unsigned(ParseTerm(999, FailBuff));
334 ParserAuxSp = (char *)tp;
335 ++nargs;
336 if (Yap_tokptr->Tok != Ord(Ponctuation_tok))
337 break;
338 if (((int) Yap_tokptr->TokInfo) != ',')
339 break;
340 NextToken;
341 }
342 ParserAuxSp = (char *)p;
343 /*
344 * Needed because the arguments for the functor are placed in reverse
345 * order
346 */
347 if (H > ASP-(nargs+1)) {
348 Yap_ErrorMessage = "Stack Overflow";
349 FAIL;
350 }
351 func = Yap_MkFunctor(a, nargs);
352 if (func == NULL) {
353 Yap_ErrorMessage = "Heap Overflow";
354 FAIL;
355 }
356 #ifdef SFUNC
357 if (pe)
358 t = MkSFTerm(Yap_MkFunctor(a, SFArity), nargs, p, pe->NilValue);
359 else
360 t = Yap_MkApplTerm(Yap_MkFunctor(a, nargs), nargs, p);
361 #else
362 if (a == AtomDBref && nargs == 2)
363 t = MkDBRefTerm((DBRef)IntegerOfTerm(p[0]));
364 else
365 t = Yap_MkApplTerm(func, nargs, p);
366 #endif
367 if (H > ASP-4096) {
368 Yap_ErrorMessage = "Stack Overflow";
369 return TermNil;
370 }
371 /* check for possible overflow against local stack */
372 checkfor((Term) ')', FailBuff);
373 return t;
374 }
375
376
377 static Term
ParseList(JMPBUFF * FailBuff)378 ParseList(JMPBUFF *FailBuff)
379 {
380 Term o;
381 CELL *to_store;
382 o = AbsPair(H);
383 loop:
384 to_store = H;
385 H+=2;
386 to_store[0] = ParseTerm(999, FailBuff);
387 if (Yap_tokptr->Tok == Ord(Ponctuation_tok)) {
388 if (((int) Yap_tokptr->TokInfo) == ',') {
389 NextToken;
390 if (Yap_tokptr->Tok == Ord(Name_tok)
391 && strcmp(RepAtom((Atom)(Yap_tokptr->TokInfo))->StrOfAE, "..") == 0) {
392 NextToken;
393 to_store[1] = ParseTerm(999, FailBuff);
394 } else {
395 /* check for possible overflow against local stack */
396 if (H > ASP-4096) {
397 to_store[1] = TermNil;
398 Yap_ErrorMessage = "Stack Overflow";
399 FAIL;
400 } else {
401 to_store[1] = AbsPair(H);
402 goto loop;
403 }
404 }
405 } else if (((int) Yap_tokptr->TokInfo) == '|') {
406 NextToken;
407 to_store[1] = ParseTerm(999, FailBuff);
408 } else {
409 to_store[1] = MkAtomTerm(AtomNil);
410 }
411 } else
412 FAIL;
413 return (o);
414 }
415
416 #ifndef INFINITY
417 #define INFINITY (1.0/0.0)
418 #endif
419
420 #ifndef NAN
421 #define NAN (0.0/0.0)
422 #endif
423
424 static Term
ParseTerm(int prio,JMPBUFF * FailBuff)425 ParseTerm(int prio, JMPBUFF *FailBuff)
426 {
427 /* parse term with priority prio */
428 Volatile Term t;
429 Volatile Functor func;
430 Volatile VarEntry *varinfo;
431 Volatile int curprio = 0, opprio, oplprio, oprprio;
432 Volatile Atom opinfo;
433
434 switch (Yap_tokptr->Tok) {
435 case Name_tok:
436 t = Yap_tokptr->TokInfo;
437 NextToken;
438 if ((Yap_tokptr->Tok != Ord(Ponctuation_tok)
439 || Unsigned(Yap_tokptr->TokInfo) != 'l')
440 && IsPrefixOp((Atom)t, &opprio, &oprprio)
441 ) {
442 /* special rules apply for +1, -2.3, etc... */
443 if (Yap_tokptr->Tok == Number_tok) {
444 if ((Atom)t == AtomMinus) {
445 t = Yap_tokptr->TokInfo;
446 if (IsIntTerm(t))
447 t = MkIntTerm(-IntOfTerm(t));
448 else if (IsFloatTerm(t))
449 t = MkFloatTerm(-FloatOfTerm(t));
450 #ifdef USE_GMP
451 else if (IsBigIntTerm(t)) {
452 t = Yap_gmp_neg_big(t);
453 }
454 #endif
455 else
456 t = MkLongIntTerm(-LongIntOfTerm(t));
457 NextToken;
458 break;
459 }
460 } else if (Yap_tokptr->Tok == Name_tok) {
461 Atom at = (Atom)Yap_tokptr->TokInfo;
462 #ifndef _MSC_VER
463 if ((Atom)t == AtomPlus) {
464 if (at == AtomInf) {
465 t = MkFloatTerm(INFINITY);
466 NextToken;
467 break;
468 } else if (at == AtomNan) {
469 t = MkFloatTerm(NAN);
470 NextToken;
471 break;
472 }
473 } else if ((Atom)t == AtomMinus) {
474 if (at == AtomInf) {
475 t = MkFloatTerm(-INFINITY);
476 NextToken;
477 break;
478 } else if (at == AtomNan) {
479 t = MkFloatTerm(NAN);
480 NextToken;
481 break;
482 }
483 }
484 #endif
485 }
486 if (opprio <= prio) {
487 /* try to parse as a prefix operator */
488 TRY(
489 /* build appl on the heap */
490 func = Yap_MkFunctor((Atom) t, 1);
491 if (func == NULL) {
492 Yap_ErrorMessage = "Heap Overflow";
493 FAIL;
494 }
495 t = ParseTerm(oprprio, FailBuff);
496 t = Yap_MkApplTerm(func, 1, &t);
497 /* check for possible overflow against local stack */
498 if (H > ASP-4096) {
499 Yap_ErrorMessage = "Stack Overflow";
500 FAIL;
501 }
502 curprio = opprio;
503 ,
504 break;
505 )
506 }
507 }
508 if (Yap_tokptr->Tok == Ord(Ponctuation_tok)
509 && Unsigned(Yap_tokptr->TokInfo) == 'l')
510 t = ParseArgs((Atom) t, FailBuff);
511 else
512 t = MkAtomTerm((Atom)t);
513 break;
514
515 case Number_tok:
516 t = Yap_tokptr->TokInfo;
517 NextToken;
518 break;
519
520 case String_tok: /* build list on the heap */
521 {
522 Volatile char *p = (char *) Yap_tokptr->TokInfo;
523 if (*p == 0)
524 t = MkAtomTerm(AtomNil);
525 else if (yap_flags[YAP_DOUBLE_QUOTES_FLAG] == STRING_AS_CHARS)
526 t = Yap_StringToListOfAtoms(p);
527 else if (yap_flags[YAP_DOUBLE_QUOTES_FLAG] == STRING_AS_ATOM) {
528 Atom at = Yap_LookupAtom(p);
529 if (at == NIL) {
530 Yap_ErrorMessage = "Heap Overflow";
531 FAIL;
532 }
533 t = MkAtomTerm(at);
534 } else
535 t = Yap_StringToList(p);
536 NextToken;
537 }
538 break;
539
540 case WString_tok: /* build list on the heap */
541 {
542 Volatile wchar_t *p = (wchar_t *) Yap_tokptr->TokInfo;
543 if (*p == 0)
544 t = MkAtomTerm(AtomNil);
545 else if (yap_flags[YAP_DOUBLE_QUOTES_FLAG] == STRING_AS_CHARS)
546 t = Yap_WideStringToListOfAtoms(p);
547 else if (yap_flags[YAP_DOUBLE_QUOTES_FLAG] == STRING_AS_ATOM)
548 t = MkAtomTerm(Yap_LookupWideAtom(p));
549 else
550 t = Yap_WideStringToList(p);
551 NextToken;
552 }
553 break;
554
555 case Var_tok:
556 varinfo = (VarEntry *) (Yap_tokptr->TokInfo);
557 if ((t = varinfo->VarAdr) == TermNil) {
558 t = varinfo->VarAdr = MkVarTerm();
559 }
560 NextToken;
561 break;
562
563 case Error_tok:
564 FAIL;
565
566 case Ponctuation_tok:
567 switch ((int) Yap_tokptr->TokInfo) {
568 case '(':
569 case 'l': /* non solo ( */
570 NextToken;
571 t = ParseTerm(1200, FailBuff);
572 checkfor((Term) ')', FailBuff);
573 break;
574 case '[':
575 NextToken;
576 t = ParseList(FailBuff);
577 checkfor((Term) ']', FailBuff);
578 break;
579 case '{':
580 NextToken;
581 t = ParseTerm(1200, FailBuff);
582 t = Yap_MkApplTerm(FunctorBraces, 1, &t);
583 /* check for possible overflow against local stack */
584 if (H > ASP-4096) {
585 Yap_ErrorMessage = "Stack Overflow";
586 FAIL;
587 }
588 checkfor((Term) '}', FailBuff);
589 break;
590 default:
591 FAIL;
592 }
593 break;
594
595 default:
596
597 FAIL;
598 }
599
600 /* main loop to parse infix and posfix operators starts here */
601 while (TRUE) {
602 if (Yap_tokptr->Tok == Ord(Name_tok)
603 && Yap_HasOp((Atom)(Yap_tokptr->TokInfo))) {
604 Atom save_opinfo = opinfo = (Atom)(Yap_tokptr->TokInfo);
605 if (IsInfixOp(save_opinfo, &opprio, &oplprio, &oprprio)
606 && opprio <= prio && oplprio >= curprio) {
607 /* try parsing as infix operator */
608 Volatile int oldprio = curprio;
609 TRY3(
610 func = Yap_MkFunctor((Atom) Yap_tokptr->TokInfo, 2);
611 if (func == NULL) {
612 Yap_ErrorMessage = "Heap Overflow";
613 FAIL;
614 }
615 NextToken;
616 {
617 Term args[2];
618 args[0] = t;
619 args[1] = ParseTerm(oprprio, FailBuff);
620 t = Yap_MkApplTerm(func, 2, args);
621 /* check for possible overflow against local stack */
622 if (H > ASP-4096) {
623 Yap_ErrorMessage = "Stack Overflow";
624 FAIL;
625 }
626 },
627 curprio = opprio;
628 opinfo = save_opinfo;
629 continue;
630 ,
631 opinfo = save_opinfo;
632 curprio = oldprio;
633 )
634 }
635 if (IsPosfixOp(opinfo, &opprio, &oplprio)
636 && opprio <= prio && oplprio >= curprio) {
637 /* parse as posfix operator */
638 Functor func = Yap_MkFunctor((Atom) Yap_tokptr->TokInfo, 1);
639 if (func == NULL) {
640 Yap_ErrorMessage = "Heap Overflow";
641 FAIL;
642 }
643 t = Yap_MkApplTerm(func, 1, &t);
644 /* check for possible overflow against local stack */
645 if (H > ASP-4096) {
646 Yap_ErrorMessage = "Stack Overflow";
647 FAIL;
648 }
649 curprio = opprio;
650 NextToken;
651 continue;
652 }
653 break;
654 }
655 if (Yap_tokptr->Tok == Ord(Ponctuation_tok)) {
656 if (Unsigned(Yap_tokptr->TokInfo) == ',' &&
657 prio >= 1000 && curprio <= 999) {
658 Volatile Term args[2];
659 NextToken;
660 args[0] = t;
661 args[1] = ParseTerm(1000, FailBuff);
662 t = Yap_MkApplTerm(FunctorComma, 2, args);
663 /* check for possible overflow against local stack */
664 if (H > ASP-4096) {
665 Yap_ErrorMessage = "Stack Overflow";
666 FAIL;
667 }
668 curprio = 1000;
669 continue;
670 } else if (Unsigned(Yap_tokptr->TokInfo) == '|' &&
671 IsInfixOp(AtomVBar, &opprio, &oplprio, &oprprio)
672 && opprio <= prio && oplprio >= curprio) {
673 Volatile Term args[2];
674 NextToken;
675 args[0] = t;
676 args[1] = ParseTerm(oprprio, FailBuff);
677 t = Yap_MkApplTerm(FunctorVBar, 2, args);
678 /* check for possible overflow against local stack */
679 if (H > ASP-4096) {
680 Yap_ErrorMessage = "Stack Overflow";
681 FAIL;
682 }
683 curprio = opprio;
684 continue;
685 }
686 }
687 if (Yap_tokptr->Tok <= Ord(WString_tok))
688 FAIL;
689 break;
690 }
691 #ifdef DEBUG
692 if (Yap_Option['p' - 'a' + 1]) {
693 Yap_DebugPutc(Yap_c_error_stream,'[');
694 Yap_DebugPlWrite(t);
695 Yap_DebugPutc(Yap_c_error_stream,']');
696 Yap_DebugPutc(Yap_c_error_stream,'\n');
697 }
698 #endif
699 return t;
700 }
701
702
703 Term
Yap_Parse(void)704 Yap_Parse(void)
705 {
706 Volatile Term t;
707 JMPBUFF FailBuff;
708
709 if (!sigsetjmp(FailBuff.JmpBuff, 0)) {
710 t = ParseTerm(1200, &FailBuff);
711 if (Yap_tokptr->Tok != Ord(eot_tok))
712 return (0L);
713 return (t);
714 } else
715 return (0);
716 }
717