FORM v5.0.1-23-g7a8f756
if.c
Go to the documentation of this file.
1
5/* #[ License : */
6/*
7 * Copyright (C) 1984-2026 J.A.M. Vermaseren
8 * When using this file you are requested to refer to the publication
9 * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
10 * This is considered a matter of courtesy as the development was paid
11 * for by FOM the Dutch physics granting agency and we would like to
12 * be able to track its scientific use to convince FOM of its value
13 * for the community.
14 *
15 * This file is part of FORM.
16 *
17 * FORM is free software: you can redistribute it and/or modify it under the
18 * terms of the GNU General Public License as published by the Free Software
19 * Foundation, either version 3 of the License, or (at your option) any later
20 * version.
21 *
22 * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
23 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
24 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
25 * details.
26 *
27 * You should have received a copy of the GNU General Public License along
28 * with FORM. If not, see <http://www.gnu.org/licenses/>.
29 */
30/* #] License : */
31/*
32 #[ Includes : if.c
33*/
34
35#include "form3.h"
36
37/*
38 #] Includes :
39 #[ If statement :
40 #[ Syntax :
41
42 The `if' is a conglomerate of statements: if,else,endif
43
44 The if consists in principle of:
45
46 if ( number );
47 statements
48 else;
49 statements
50 endif;
51
52 The first set is taken when number != 0.
53 The else is not mandatory.
54 TRUE = 1 and FALSE = 0
55
56 The number can be built up via a logical expression:
57
58 expr1 condition expr2
59
60 each expression can be a subexpression again. It has to be
61 enclosed in parentheses in that case.
62 Conditions are:
63 >, >=, <, <=, ==, !=, ||, &&
64
65 When Expressions are chained evaluation is from left to right,
66 independent of whether this indicates nonsense.
67 if ( a || b || c || d ); is a perfectly normal statement.
68 if ( a >= b || c == d ); would be messed up. This should be:
69 if ( ( a >= b ) || ( c == d ) );
70
71 The building blocks of the Expressions are:
72
73 Match(option,pattern) The number of times pattern fits in term_
74 Count(....) The count value of term_
75 Coeff[icient] The coefficient of term_
76 FindLoop(options) Are there loops (as in ReplaceLoop).
77
78 Implementation for internal notation:
79
80 TYPEIF,length,gotolevel(if fail),EXPRTYPE,length,......
81
82 EXPRTYPE can be:
83 SHORTNUMBER ->,4,sign,size
84 LONGNUMBER ->,|ncoef+2|,ncoef,numer,denom
85 MATCH ->,patternsiz+3,keyword,pattern
86 MULTIPLEOF ->,3,thenumber
87 COUNT ->,countsiz+2,countinfo
88 TYPEFINDLOOP ->,7 (findloop info)
89 COEFFICIENT ->,2
90 IFDOLLAR ->,3,dollarnumber
91 SUBEXPR ->,size,dummy,size1,EXPRTYPE,length,...
92 ,2,condition1,size2,...
93 This is like functions.
94
95 Note that there must be a restriction to the number of nestings
96 of parentheses in an if statement. It has been set to 10.
97
98 The syntax of match corresponds to the syntax of the left side
99 of an id statement. The only difference is the keyword
100 MATCH vs TYPEIDNEW.
101
102 #] Syntax :
103 #[ GetIfDollarNum :
104*/
105
106WORD GetIfDollarNum(WORD *ifp, WORD *ifstop)
107{
108 DOLLARS d;
109 WORD num, *w;
110 if ( ifp[2] < 0 ) { return(-ifp[2]-1); }
111 d = Dollars+ifp[2];
112 if ( ifp+3 < ifstop && ifp[3] == IFDOLLAREXTRA ) {
113 if ( d->nfactors == 0 ) {
114 MLOCK(ErrorMessageLock);
115 MesPrint("Attempt to use a factor of an unfactored $-variable");
116 MUNLOCK(ErrorMessageLock);
117 Terminate(-1);
118 }
119 num = GetIfDollarNum(ifp+3,ifstop);
120 if ( num > d->nfactors ) {
121 MLOCK(ErrorMessageLock);
122 MesPrint("Dollar factor number %s out of range",num);
123 MUNLOCK(ErrorMessageLock);
124 Terminate(-1);
125 }
126 if ( num == 0 ) {
127 return(d->nfactors);
128 }
129 w = d->factors[num-1].where;
130 if ( w == 0 ) return(d->factors[num].value);
131getnumber:;
132 if ( *w == 0 ) return(0);
133 if ( *w == 4 && w[3] == 3 && w[2] == 1 && w[1] < MAXPOSITIVE && w[4] == 0 ) {
134 return(w[1]);
135 }
136 if ( ( w[w[0]] != 0 ) || ( ABS(w[w[0]-1]) != w[0]-1 ) ) {
137 MLOCK(ErrorMessageLock);
138 MesPrint("Dollar factor number expected but found expression");
139 MUNLOCK(ErrorMessageLock);
140 Terminate(-1);
141 }
142 else {
143 MLOCK(ErrorMessageLock);
144 MesPrint("Dollar factor number out of range");
145 MUNLOCK(ErrorMessageLock);
146 Terminate(-1);
147 }
148 return(0);
149 }
150/*
151 Now we have just a dollar and should evaluate that into a short number
152*/
153 if ( d->type == DOLZERO ) {
154 return(0);
155 }
156 else if ( d->type == DOLNUMBER || d->type == DOLTERMS ) {
157 w = d->where; goto getnumber;
158 }
159 else {
160 MLOCK(ErrorMessageLock);
161 MesPrint("Dollar factor number is wrong type");
162 MUNLOCK(ErrorMessageLock);
163 Terminate(-1);
164 return(0);
165 }
166}
167
168/*
169 #] GetIfDollarNum :
170 #[ FindVar :
171*/
172
173int FindVar(WORD *v, WORD *term)
174{
175 WORD *t, *tstop, *m, *mstop, *f, *fstop, *a, *astop;
176 GETSTOP(term,tstop);
177 t = term+1;
178 while ( t < tstop ) {
179 if ( *v == *t && *v < FUNCTION ) { /* VECTOR, INDEX, SYMBOL, DOTPRODUCT */
180 switch ( *v ) {
181 case SYMBOL:
182 m = t+2; mstop = t+t[1];
183 while ( m < mstop ) {
184 if ( *m == v[1] ) return(1);
185 m += 2;
186 }
187 break;
188 case INDEX:
189 case VECTOR:
190InVe:
191 m = t+2; mstop = t+t[1];
192 while ( m < mstop ) {
193 if ( *m == v[1] ) return(1);
194 m++;
195 }
196 break;
197 case DOTPRODUCT:
198 m = t+2; mstop = t+t[1];
199 while ( m < mstop ) {
200 if ( *m == v[1] && m[1] == v[2] ) return(1);
201 if ( *m == v[2] && m[1] == v[1] ) return(1);
202 m += 3;
203 }
204 break;
205 }
206 }
207 else if ( *v == VECTOR && *t == INDEX ) goto InVe;
208 else if ( *v == INDEX && *t == VECTOR ) goto InVe;
209 else if ( ( *v == VECTOR || *v == INDEX ) && *t == DOTPRODUCT ) {
210 m = t+2; mstop = t+t[1];
211 while ( m < mstop ) {
212 if ( v[1] == m[0] || v[1] == m[1] ) return(1);
213 m += 3;
214 }
215 }
216 else if ( *t >= FUNCTION ) {
217 if ( *v == FUNCTION && v[1] == *t ) return(1);
218 if ( functions[*t-FUNCTION].spec > 0 ) {
219 if ( *v == VECTOR || *v == INDEX ) { /* we need to check arguments */
220 int i;
221 for ( i = FUNHEAD; i < t[1]; i++ ) {
222 if ( v[1] == t[i] ) return(1);
223 }
224 }
225 }
226 else {
227 fstop = t + t[1]; f = t + FUNHEAD;
228 while ( f < fstop ) { /* Do the arguments one by one */
229 if ( *f <= 0 ) {
230 switch ( *f ) {
231 case -SYMBOL:
232 if ( *v == SYMBOL && v[1] == f[1] ) return(1);
233 f += 2;
234 break;
235 case -VECTOR:
236 case -MINVECTOR:
237 case -INDEX:
238 if ( ( *v == VECTOR || *v == INDEX )
239 && ( v[1] == f[1] ) ) return(1);
240 f += 2;
241 break;
242 case -SNUMBER:
243 f += 2;
244 break;
245 default:
246 if ( *v == FUNCTION && v[1] == -*f && *f <= -FUNCTION ) return(1);
247 if ( *f <= -FUNCTION ) f++;
248 else f += 2;
249 break;
250 }
251 }
252 else {
253 a = f + ARGHEAD; astop = f + *f;
254 while ( a < astop ) {
255 if ( FindVar(v,a) == 1 ) return(1);
256 a += *a;
257 }
258 f = astop;
259 }
260 }
261 }
262 }
263 t += t[1];
264 }
265 return(0);
266}
267
268/*
269 #] FindVar :
270 #[ DoIfStatement : WORD DoIfStatement(PHEAD ifcode,term)
271
272 The execution time part of the if-statement.
273 The arguments are a pointer to the TYPEIF and a pointer to the term.
274 The answer is either 1 (success) or 0 (fail).
275 The calling routine can figure out where to go in case of failure
276 by picking up gotolevel.
277 Note that the whole setup asks for recursions.
278*/
279
280int DoIfStatement(PHEAD WORD *ifcode, WORD *term)
281{
282 GETBIDENTITY
283 WORD *ifstop, *ifp;
284 UWORD *coef1 = 0, *coef2, *coef3, *cc;
285 WORD ncoef1, ncoef2, ncoef3, i = 0, first, *r, acoef, ismul1, ismul2, j;
286 UWORD *Spac1, *Spac2;
287 ifstop = ifcode + ifcode[1];
288 ifp = ifcode + 3;
289 if ( ifp >= ifstop ) return(1);
290 if ( ( ifp + ifp[1] ) >= ifstop ) {
291 switch ( *ifp ) {
292 case LONGNUMBER:
293 if ( ifp[2] ) return(1);
294 else return(0);
295 case MATCH:
296 case TYPEIF:
297 if ( HowMany(BHEAD ifp,term) ) return(1);
298 else return(0);
299 case TYPEFINDLOOP:
300 if ( Lus(term,ifp[3],ifp[4],ifp[5],ifp[6],ifp[2]) ) return(1);
301 else return(0);
302 case TYPECOUNT:
303 if ( CountDo(term,ifp) ) return(1);
304 else return(0);
305 case COEFFI:
306 case MULTIPLEOF:
307 return(1);
308 case IFDOLLAR:
309 {
310 DOLLARS d = Dollars + ifp[2];
311#ifdef WITHPTHREADS
312 int nummodopt, dtype = -1;
313 if ( AS.MultiThreaded ) {
314 for ( nummodopt = 0; nummodopt < NumModOptdollars; nummodopt++ ) {
315 if ( ifp[2] == ModOptdollars[nummodopt].number ) break;
316 }
317 if ( nummodopt < NumModOptdollars ) {
318 dtype = ModOptdollars[nummodopt].type;
319 if ( DollarLocalCopy(dtype) ) {
320 d = ModOptdollars[nummodopt].dstruct+AT.identity;
321 }
322 }
323 }
324 dtype = d->type;
325#else
326 int dtype = d->type; /* We use dtype to make the operation atomic */
327#endif
328 if ( dtype == DOLZERO ) return(0);
329 if ( dtype == DOLUNDEFINED ) {
330 if ( AC.UnsureDollarMode == 0 ) {
331 MesPrint("$%s is undefined",AC.dollarnames->namebuffer+d->name);
332 Terminate(-1);
333 }
334 }
335 }
336 return(1);
337 case IFEXPRESSION:
338 r = ifp+2; j = ifp[1] - 2;
339 while ( --j >= 0 ) {
340 if ( *r == AR.CurExpr ) return(1);
341 r++;
342 }
343 return(0);
344 case IFISFACTORIZED:
345 r = ifp+2; j = ifp[1] - 2;
346 if ( j == 0 ) {
347 if ( ( Expressions[AR.CurExpr].vflags & ISFACTORIZED ) != 0 )
348 return(1);
349 else
350 return(0);
351 }
352 while ( --j >= 0 ) {
353 if ( ( Expressions[*r].vflags & ISFACTORIZED ) == 0 ) return(0);
354 r++;
355 }
356 return(1);
357 case IFOCCURS:
358 {
359 WORD *OccStop = ifp + ifp[1];
360 ifp += 2;
361 while ( ifp < OccStop ) {
362 if ( FindVar(ifp,term) == 1 ) return(1);
363 if ( *ifp == DOTPRODUCT ) ifp += 3;
364 else ifp += 2;
365 }
366 }
367 return(0);
368 case IFUSERFLAG:
369 if ( ( Expressions[AR.CurExpr].uflags & (1 << ifp[2]) ) != 0 )
370 return(1);
371 return(0);
372 default:
373/*
374 Now we have a subexpression. Test first for one with a single item.
375*/
376 if ( ifp[3] == ( ifp[1] + 3 ) ) return(DoIfStatement(BHEAD ifp,term));
377 ifstop = ifp + ifp[1];
378 ifp += 3;
379 break;
380 }
381 }
382/*
383 Here is the composite condition.
384*/
385 coef3 = NumberMalloc("DoIfStatement");
386 Spac1 = NumberMalloc("DoIfStatement");
387 Spac2 = (UWORD *)(TermMalloc("DoIfStatement"));
388 ncoef1 = 0; first = 1; ismul1 = 0;
389 do {
390 if ( !first ) {
391 ifp += 2;
392 if ( ifp[-2] == ORCOND && ncoef1 ) {
393 coef1 = Spac1;
394 ncoef1 = 1; coef1[0] = coef1[1] = 1;
395 goto SkipCond;
396 }
397 if ( ifp[-2] == ANDCOND && !ncoef1 ) goto SkipCond;
398 }
399 coef2 = Spac2;
400 ncoef2 = 1;
401 ismul2 = 0;
402 switch ( *ifp ) {
403 case LONGNUMBER:
404 ncoef2 = ifp[2];
405 j = 2*(ABS(ncoef2));
406 cc = (UWORD *)(ifp + 3);
407 for ( i = 0; i < j; i++ ) coef2[i] = cc[i];
408 break;
409#ifdef WITHFLOAT
410/* UNFINISHED_FEATURE_EXCL_START */
411 case IFFLOATNUMBER:
412/*
413 The sloppy solution is: Convert to rational.
414 This way we can write it over coef2,ncoef2
415*/
416 ncoef2 = FloatFunToRat(BHEAD coef2,ifp);
417 break;
418/* UNFINISHED_FEATURE_EXCL_STOP */
419#endif
420 case MATCH:
421 case TYPEIF:
422 coef2[0] = HowMany(BHEAD ifp,term);
423 coef2[1] = 1;
424 if ( coef2[0] == 0 ) ncoef2 = 0;
425 break;
426 case TYPECOUNT:
427 acoef = CountDo(term,ifp);
428 coef2[0] = ABS(acoef);
429 coef2[1] = 1;
430 if ( acoef == 0 ) ncoef2 = 0;
431 else if ( acoef < 0 ) ncoef2 = -1;
432 break;
433 case TYPEFINDLOOP:
434 acoef = Lus(term,ifp[3],ifp[4],ifp[5],ifp[6],ifp[2]);
435 coef2[0] = ABS(acoef);
436 coef2[1] = 1;
437 if ( acoef == 0 ) ncoef2 = 0;
438 else if ( acoef < 0 ) ncoef2 = -1;
439 break;
440 case COEFFI:
441 r = term + *term;
442 ncoef2 = r[-1];
443 i = ABS(ncoef2);
444 cc = (UWORD *)(r - i);
445 if ( ncoef2 < 0 ) ncoef2 = (ncoef2+1)>>1;
446 else ncoef2 = (ncoef2-1)>>1;
447 i--; for ( j = 0; j < i; j++ ) coef2[j] = cc[j];
448 break;
449 case SUBEXPR:
450 ncoef2 = coef2[0] = DoIfStatement(BHEAD ifp,term);
451 coef2[1] = 1;
452 break;
453 case MULTIPLEOF:
454 ncoef2 = 1;
455 coef2[0] = ifp[2];
456 coef2[1] = 1;
457 ismul2 = 1;
458 break;
459 case IFDOLLAREXTRA:
460 break;
461 case IFDOLLAR:
462 {
463/*
464 We need to abstract a long rational in coef2
465 with length ncoef2. What if that cannot be done?
466*/
467 DOLLARS d = Dollars + ifp[2];
468#ifdef WITHPTHREADS
469 int nummodopt, dtype = -1;
470 if ( AS.MultiThreaded ) {
471 for ( nummodopt = 0; nummodopt < NumModOptdollars; nummodopt++ ) {
472 if ( ifp[2] == ModOptdollars[nummodopt].number ) break;
473 }
474 if ( nummodopt < NumModOptdollars ) {
475 dtype = ModOptdollars[nummodopt].type;
476 if ( DollarLocalCopy(dtype) ) {
477 d = ModOptdollars[nummodopt].dstruct+AT.identity;
478 }
479 else {
480 LOCK(d->pthreadslock);
481 }
482 }
483 }
484#endif
485/*
486 We have to pick up the IFDOLLAREXTRA pieces for [1], [$y] etc.
487*/
488 if ( ifp+3 < ifstop && ifp[3] == IFDOLLAREXTRA ) {
489 if ( d->nfactors == 0 ) {
490 MLOCK(ErrorMessageLock);
491 MesPrint("Attempt to use a factor of an unfactored $-variable");
492 MUNLOCK(ErrorMessageLock);
493 Terminate(-1);
494 } {
495 WORD num = GetIfDollarNum(ifp+3,ifstop);
496 WORD *w;
497 while ( ifp+3 < ifstop && ifp[3] == IFDOLLAREXTRA ) ifp += 3;
498 if ( num > d->nfactors ) {
499 MLOCK(ErrorMessageLock);
500 MesPrint("Dollar factor number %s out of range",num);
501 MUNLOCK(ErrorMessageLock);
502 Terminate(-1);
503 }
504 if ( num == 0 ) {
505 ncoef2 = 1; coef2[0] = d->nfactors; coef2[1] = 1;
506 break;
507 }
508 w = d->factors[num-1].where;
509 if ( w == 0 ) {
510 if ( d->factors[num-1].value < 0 ) {
511 ncoef2 = -1; coef2[0] = -d->factors[num-1].value; coef2[1] = 1;
512 }
513 else {
514 ncoef2 = 1; coef2[0] = d->factors[num-1].value; coef2[1] = 1;
515 }
516 break;
517 }
518 if ( w[*w] == 0 ) {
519 r = w + *w - 1;
520 i = ABS(*r);
521 if ( i == ( *w-1 ) ) {
522 ncoef2 = (i-1)/2;
523 if ( *r < 0 ) ncoef2 = -ncoef2;
524 i--; cc = coef2; r = w + 1;
525 while ( --i >= 0 ) *cc++ = (UWORD)(*r++);
526 break;
527 }
528 }
529 goto generic;
530 }
531 }
532 else {
533 switch ( d->type ) {
534 case DOLUNDEFINED:
535 if ( AC.UnsureDollarMode == 0 ) {
536#ifdef WITHPTHREADS
537 if ( dtype > 0 && ! DollarLocalCopy(dtype) ) {
538 UNLOCK(d->pthreadslock);
539 }
540#endif
541 MLOCK(ErrorMessageLock);
542 MesPrint("$%s is undefined",AC.dollarnames->namebuffer+d->name);
543 MUNLOCK(ErrorMessageLock);
544 Terminate(-1);
545 }
546 ncoef2 = 0; coef2[0] = 0; coef2[1] = 1;
547 break;
548 case DOLZERO:
549 ncoef2 = coef2[0] = 0; coef2[1] = 1;
550 break;
551 case DOLSUBTERM:
552 if ( d->where[0] != INDEX || d->where[1] != 3
553 || d->where[2] < 0 || d->where[2] >= AM.OffsetIndex ) {
554 if ( AC.UnsureDollarMode == 0 ) {
555#ifdef WITHPTHREADS
556 if ( dtype > 0 && ! DollarLocalCopy(dtype) ) {
557 UNLOCK(d->pthreadslock);
558 }
559#endif
560 MLOCK(ErrorMessageLock);
561 MesPrint("$%s is of wrong type",AC.dollarnames->namebuffer+d->name);
562 MUNLOCK(ErrorMessageLock);
563 Terminate(-1);
564 }
565 ncoef2 = 0; coef2[0] = 0; coef2[1] = 1;
566 break;
567 }
568 d->index = d->where[2];
569 /* fall through */
570 case DOLINDEX:
571 if ( d->index == 0 ) {
572 ncoef2 = coef2[0] = 0; coef2[1] = 1;
573 }
574 else if ( d->index > 0 && d->index < AM.OffsetIndex ) {
575 ncoef2 = 1; coef2[0] = d->index; coef2[1] = 1;
576 }
577 else if ( AC.UnsureDollarMode == 0 ) {
578#ifdef WITHPTHREADS
579 if ( dtype > 0 && ! DollarLocalCopy(dtype) ) {
580 UNLOCK(d->pthreadslock);
581 }
582#endif
583 MLOCK(ErrorMessageLock);
584 MesPrint("$%s is of wrong type",AC.dollarnames->namebuffer+d->name);
585 MUNLOCK(ErrorMessageLock);
586 Terminate(-1);
587 }
588 ncoef2 = coef2[0] = 0; coef2[1] = 1;
589 break;
590 case DOLWILDARGS:
591 if ( d->where[0] <= -FUNCTION ||
592 ( d->where[0] < 0 && d->where[2] != 0 )
593 || ( d->where[0] > 0 && d->where[d->where[0]] != 0 )
594 ) {
595 if ( AC.UnsureDollarMode == 0 ) {
596#ifdef WITHPTHREADS
597 if ( dtype > 0 && ! DollarLocalCopy(dtype) ) {
598 UNLOCK(d->pthreadslock);
599 }
600#endif
601 MLOCK(ErrorMessageLock);
602 MesPrint("$%s is of wrong type",AC.dollarnames->namebuffer+d->name);
603 MUNLOCK(ErrorMessageLock);
604 Terminate(-1);
605 }
606 ncoef2 = coef2[0] = 0; coef2[1] = 1;
607 break;
608 }
609 /* fall through */
610 case DOLARGUMENT:
611 if ( d->where[0] == -SNUMBER ) {
612 if ( d->where[1] == 0 ) {
613 ncoef2 = coef2[0] = 0;
614 }
615 else if ( d->where[1] < 0 ) {
616 ncoef2 = -1;
617 coef2[0] = -d->where[1];
618 }
619 else {
620 ncoef2 = 1;
621 coef2[0] = d->where[1];
622 }
623 coef2[1] = 1;
624 }
625 else if ( d->where[0] == -INDEX
626 && d->where[1] >= 0 && d->where[1] < AM.OffsetIndex ) {
627 if ( d->where[1] == 0 ) {
628 ncoef2 = coef2[0] = 0; coef2[1] = 1;
629 }
630 else {
631 ncoef2 = 1; coef2[0] = d->where[1];
632 coef2[1] = 1;
633 }
634 }
635 else if ( d->where[0] > 0
636 && d->where[ARGHEAD] == (d->where[0]-ARGHEAD)
637 && ABS(d->where[d->where[0]-1]) ==
638 (d->where[0] - ARGHEAD-1) ) {
639 i = d->where[d->where[0]-1];
640 ncoef2 = (ABS(i)-1)/2;
641 if ( i < 0 ) { ncoef2 = -ncoef2; i = -i; }
642 i--; cc = coef2; r = d->where + ARGHEAD+1;
643 while ( --i >= 0 ) *cc++ = (UWORD)(*r++);
644 }
645 else {
646 if ( AC.UnsureDollarMode == 0 ) {
647#ifdef WITHPTHREADS
648 if ( dtype > 0 && ! DollarLocalCopy(dtype) ) {
649 UNLOCK(d->pthreadslock);
650 }
651#endif
652 MLOCK(ErrorMessageLock);
653 MesPrint("$%s is of wrong type",AC.dollarnames->namebuffer+d->name);
654 MUNLOCK(ErrorMessageLock);
655 Terminate(-1);
656 }
657 ncoef2 = 0; coef2[0] = 0; coef2[1] = 1;
658 }
659 break;
660 case DOLNUMBER:
661 case DOLTERMS:
662 if ( d->where[d->where[0]] == 0 ) {
663 r = d->where + d->where[0]-1;
664 i = ABS(*r);
665 if ( i == ( d->where[0]-1 ) ) {
666 ncoef2 = (i-1)/2;
667 if ( *r < 0 ) ncoef2 = -ncoef2;
668 i--; cc = coef2; r = d->where + 1;
669 while ( --i >= 0 ) *cc++ = (UWORD)(*r++);
670 break;
671 }
672 }
673generic:;
674 if ( AC.UnsureDollarMode == 0 ) {
675#ifdef WITHPTHREADS
676 if ( dtype > 0 && ! DollarLocalCopy(dtype) ) {
677 UNLOCK(d->pthreadslock);
678 }
679#endif
680 MLOCK(ErrorMessageLock);
681 MesPrint("$%s is of wrong type",AC.dollarnames->namebuffer+d->name);
682 MUNLOCK(ErrorMessageLock);
683 Terminate(-1);
684 }
685 ncoef2 = 0; coef2[0] = 0; coef2[1] = 1;
686 break;
687 }
688 }
689#ifdef WITHPTHREADS
690 if ( dtype > 0 && ! DollarLocalCopy(dtype) ) {
691 UNLOCK(d->pthreadslock);
692 }
693#endif
694 }
695 break;
696 case IFEXPRESSION:
697 r = ifp+2; j = ifp[1] - 2; ncoef2 = 0;
698 while ( --j >= 0 ) {
699 if ( *r == AR.CurExpr ) { ncoef2 = 1; break; }
700 r++;
701 }
702 coef2[0] = ncoef2;
703 coef2[1] = 1;
704 break;
705 case IFISFACTORIZED:
706 r = ifp+2; j = ifp[1] - 2;
707 if ( j == 0 ) {
708 ncoef2 = 0;
709 if ( ( Expressions[AR.CurExpr].vflags & ISFACTORIZED ) != 0 ) {
710 ncoef2 = 1;
711 }
712 }
713 else {
714 ncoef2 = 1;
715 while ( --j >= 0 ) {
716 if ( ( Expressions[*r].vflags & ISFACTORIZED ) == 0 ) {
717 ncoef2 = 0;
718 break;
719 }
720 r++;
721 }
722 }
723 coef2[0] = ncoef2;
724 coef2[1] = 1;
725 break;
726 case IFOCCURS:
727 {
728 WORD *OccStop = ifp + ifp[1], *ifpp = ifp+2;
729 ncoef2 = 0;
730 while ( ifpp < OccStop ) {
731 if ( FindVar(ifpp,term) == 1 ) {
732 ncoef2 = 1; break;
733 }
734 if ( *ifpp == DOTPRODUCT ) ifp += 3;
735 else ifpp += 2;
736 }
737 coef2[0] = ncoef2;
738 coef2[1] = 1;
739 }
740 break;
741 case IFUSERFLAG:
742 {
743 ncoef2 = 0;
744 if ( ( Expressions[AR.CurExpr].uflags & (1 << ifp[2]) ) != 0 )
745 ncoef2 = 1;
746 coef2[0] = ncoef2;
747 coef2[1] = 1;
748 }
749 break;
750 default:
751 break;
752 }
753 if ( !first ) {
754 if ( ifp[-2] != ORCOND && ifp[-2] != ANDCOND ) {
755 if ( ( ifp[-2] == EQUAL || ifp[-2] == NOTEQUAL ) &&
756 ( ismul2 || ismul1 ) ) {
757 if ( ismul1 && ismul2 ) {
758 if ( coef1[0] == coef2[0] ) i = 1;
759 else i = 0;
760 }
761 else {
762 if ( ismul1 ) {
763 if ( ncoef2 )
764 Divvy(BHEAD coef2,&ncoef2,coef1,ncoef1);
765 cc = coef2; ncoef3 = ncoef2;
766 }
767 else {
768 if ( ncoef1 )
769 Divvy(BHEAD coef1,&ncoef1,coef2,ncoef2);
770 cc = coef1; ncoef3 = ncoef1;
771 }
772 if ( ncoef3 < 0 ) ncoef3 = -ncoef3;
773 if ( ncoef3 == 0 ) {
774 if ( ifp[-2] == EQUAL ) i = 1;
775 else i = 0;
776 }
777 else if ( cc[ncoef3] != 1 ) {
778 if ( ifp[-2] == EQUAL ) i = 0;
779 else i = 1;
780 }
781 else {
782 for ( j = 1; j < ncoef3; j++ ) {
783 if ( cc[ncoef3+j] != 0 ) break;
784 }
785 if ( j < ncoef3 ) {
786 if ( ifp[-2] == EQUAL ) i = 0;
787 else i = 1;
788 }
789 else if ( ifp[-2] == EQUAL ) i = 1;
790 else i = 0;
791 }
792 }
793 goto donemul;
794 }
795 else if ( AddRat(BHEAD coef1,ncoef1,coef2,-ncoef2,coef3,&ncoef3) ) {
796 NumberFree(coef3,"DoIfStatement"); NumberFree(Spac1,"DoIfStatement"); TermFree(Spac2,"DoIfStatement");
797 MesCall("DoIfStatement"); return(-1);
798 }
799 switch ( ifp[-2] ) {
800 case GREATER:
801 if ( ncoef3 > 0 ) i = 1;
802 else i = 0;
803 break;
804 case GREATEREQUAL:
805 if ( ncoef3 >= 0 ) i = 1;
806 else i = 0;
807 break;
808 case LESS:
809 if ( ncoef3 < 0 ) i = 1;
810 else i = 0;
811 break;
812 case LESSEQUAL:
813 if ( ncoef3 <= 0 ) i = 1;
814 else i = 0;
815 break;
816 case EQUAL:
817 if ( ncoef3 == 0 ) i = 1;
818 else i = 0;
819 break;
820 case NOTEQUAL:
821 if ( ncoef3 != 0 ) i = 1;
822 else i = 0;
823 break;
824 }
825donemul: if ( i ) { ncoef2 = 1; coef2 = Spac2; coef2[0] = coef2[1] = 1; }
826 else ncoef2 = 0;
827 ismul1 = ismul2 = 0;
828 }
829 }
830 else {
831 first = 0;
832 }
833 coef1 = Spac1;
834 i = 2*ABS(ncoef2);
835 for ( j = 0; j < i; j++ ) coef1[j] = coef2[j];
836 ncoef1 = ncoef2;
837SkipCond:
838 ifp += ifp[1];
839 } while ( ifp < ifstop );
840
841 NumberFree(coef3,"DoIfStatement"); NumberFree(Spac1,"DoIfStatement"); TermFree(Spac2,"DoIfStatement");
842 if ( ncoef1 ) return(1);
843 else return(0);
844}
845
846/*
847 #] DoIfStatement :
848 #[ HowMany : WORD HowMany(ifcode,term)
849
850 Returns the number of times that the pattern in ifcode
851 can be taken out from term. There is a subkey in ifcode[2];
852 The notation is identical to the lhs of an id statement.
853 Most of the code comes from TestMatch.
854*/
855
856WORD HowMany(PHEAD WORD *ifcode, WORD *term)
857{
858 GETBIDENTITY
859 WORD *m, *t, *r, *w, power, RetVal, i, topje, *newterm;
860 WORD *OldWork, *ww, *mm;
861 int *RepSto, RepVal;
862 int numdollars = 0;
863 m = ifcode + IDHEAD;
864 AN.FullProto = m;
865 AN.WildValue = w = m + SUBEXPSIZE;
866 m += m[1];
867 AN.WildStop = m;
868 OldWork = AT.WorkPointer;
869 if ( ( ifcode[4] & 1 ) != 0 ) { /* We have at least one dollar in the pattern */
870 AR.Eside = LHSIDEX;
871 ww = AT.WorkPointer; i = m[0]; mm = m;
872 NCOPY(ww,mm,i);
873 *OldWork += 3;
874 *ww++ = 1; *ww++ = 1; *ww++ = 3;
875 AT.WorkPointer = ww;
876 RepSto = AN.RepPoint;
877 RepVal = *RepSto;
878 NewSort(BHEAD0);
879 if ( Generator(BHEAD OldWork,AR.Cnumlhs) ) {
881 *RepSto = RepVal;
882 AN.RepPoint = RepSto;
883 AT.WorkPointer = OldWork;
884 return(-1);
885 }
886 AT.WorkPointer = ww;
887 if ( EndSort(BHEAD ww,0) < 0 ) {}
888 *RepSto = RepVal;
889 AN.RepPoint = RepSto;
890 if ( *ww == 0 || *(ww+*ww) != 0 ) {
891 if ( AP.lhdollarerror == 0 ) {
892 MLOCK(ErrorMessageLock);
893 MesPrint("&LHS must be one term");
894 MUNLOCK(ErrorMessageLock);
895 AP.lhdollarerror = 1;
896 }
897 AT.WorkPointer = OldWork;
898 return(-1);
899 }
900 m = ww; AT.WorkPointer = ww = m + *m;
901 if ( m[*m-1] < 0 ) { m[*m-1] = -m[*m-1]; }
902 *m -= m[*m-1];
903 AR.Eside = RHSIDE;
904 }
905 else {
906 ww = term + *term;
907 if ( AT.WorkPointer < ww ) AT.WorkPointer = ww;
908 }
909 ClearWild(BHEAD0);
910 while ( w < AN.WildStop ) {
911 if ( *w == LOADDOLLAR ) numdollars++;
912 w += w[1];
913 }
914 AN.RepFunNum = 0;
915 AN.RepFunList = AT.WorkPointer;
916 AT.WorkPointer = (WORD *)(((UBYTE *)(AT.WorkPointer)) + AM.MaxTer);
917 topje = cbuf[AT.ebufnum].numrhs;
918 if ( AT.WorkPointer >= AT.WorkTop ) {
919 MLOCK(ErrorMessageLock);
920 MesWork();
921 MUNLOCK(ErrorMessageLock);
922 return(-1);
923 }
924 AN.DisOrderFlag = ifcode[2] & SUBDISORDER;
925 switch ( ifcode[2] & (~SUBDISORDER) ) {
926 case SUBONLY :
927 /* Must be an exact match */
928 AN.UseFindOnly = 1; AN.ForFindOnly = 0;
929/*
930 Copy the term first to scratchterm. This is needed
931 because of the Substitute.
932*/
933 i = *term;
934 t = term; newterm = r = AT.WorkPointer;
935 NCOPY(r,t,i); AT.WorkPointer = r;
936 RetVal = 0;
937 if ( FindRest(BHEAD newterm,m) && ( AN.UsedOtherFind ||
938 FindOnly(BHEAD newterm,m) ) ) {
939 Substitute(BHEAD newterm,m,1);
940 if ( numdollars ) {
941 WildDollars(BHEAD (WORD *)0);
942 numdollars = 0;
943 }
944 ClearWild(BHEAD0);
945 RetVal = 1;
946 }
947 else RetVal = 0;
948 break;
949 case SUBMANY :
950/*
951 Copy the term first to scratchterm. This is needed
952 because of the Substitute.
953*/
954 i = *term;
955 t = term; newterm = r = AT.WorkPointer;
956 NCOPY(r,t,i); AT.WorkPointer = r;
957 RetVal = 0;
958 AN.UseFindOnly = 0;
959 if ( ( power = FindRest(BHEAD newterm,m) ) > 0 ) {
960 if ( ( power = FindOnce(BHEAD newterm,m) ) > 0 ) {
961 AN.UseFindOnly = 0;
962 do {
963 Substitute(BHEAD newterm,m,1);
964 if ( numdollars ) {
965 WildDollars(BHEAD (WORD *)0);
966 numdollars = 0;
967 }
968 ClearWild(BHEAD0);
969 RetVal++;
970 } while ( FindRest(BHEAD newterm,m) && (
971 AN.UsedOtherFind || FindOnce(BHEAD newterm,m) ) );
972 }
973 else if ( power < 0 ) {
974 do {
975 Substitute(BHEAD newterm,m,1);
976 if ( numdollars ) {
977 WildDollars(BHEAD (WORD *)0);
978 numdollars = 0;
979 }
980 ClearWild(BHEAD0);
981 RetVal++;
982 } while ( FindRest(BHEAD newterm,m) );
983 }
984 }
985 else if ( power < 0 ) {
986 if ( FindOnce(BHEAD newterm,m) ) {
987 do {
988 Substitute(BHEAD newterm,m,1);
989 if ( numdollars ) {
990 WildDollars(BHEAD (WORD *)0);
991 numdollars = 0;
992 }
993 ClearWild(BHEAD0);
994 } while ( FindOnce(BHEAD newterm,m) );
995 RetVal = 1;
996 }
997 }
998 break;
999 case SUBONCE :
1000/*
1001 Copy the term first to scratchterm. This is needed
1002 because of the Substitute.
1003*/
1004 i = *term;
1005 t = term; newterm = r = AT.WorkPointer;
1006 NCOPY(r,t,i); AT.WorkPointer = r;
1007 RetVal = 0;
1008 AN.UseFindOnly = 0;
1009 if ( FindRest(BHEAD newterm,m) && ( AN.UsedOtherFind || FindOnce(BHEAD newterm,m) ) ) {
1010 Substitute(BHEAD newterm,m,1);
1011 if ( numdollars ) {
1012 WildDollars(BHEAD (WORD *)0);
1013 numdollars = 0;
1014 }
1015 ClearWild(BHEAD0);
1016 RetVal = 1;
1017 }
1018 else RetVal = 0;
1019 break;
1020 case SUBMULTI :
1021 RetVal = FindMulti(BHEAD term,m);
1022 break;
1023 case SUBVECTOR :
1024 RetVal = 0;
1025 for ( i = 0; i < *term; i++ ) ww[i] = term[i];
1026 while ( ( power = FindAll(BHEAD ww,m,AR.Cnumlhs,ifcode) ) != 0 ) { RetVal += power; }
1027 break;
1028 case SUBSELECT :
1029 ifcode += IDHEAD; ifcode += ifcode[1]; ifcode += *ifcode;
1030 AN.UseFindOnly = 1; AN.ForFindOnly = ifcode;
1031 if ( FindRest(BHEAD term,m) && ( AN.UsedOtherFind ||
1032 FindOnly(BHEAD term,m) ) ) RetVal = 1;
1033 else RetVal = 0;
1034 break;
1035 default :
1036 RetVal = 0;
1037 break;
1038 }
1039 AT.WorkPointer = AN.RepFunList;
1040 cbuf[AT.ebufnum].numrhs = topje;
1041 return(RetVal);
1042}
1043
1044/*
1045 #] HowMany :
1046 #[ DoubleIfBuffers :
1047*/
1048
1049void DoubleIfBuffers(void)
1050{
1051 int newmax, i;
1052 WORD *newsumcheck;
1053 LONG *newheap, *newifcount;
1054 if ( AC.MaxIf == 0 ) newmax = 10;
1055 else newmax = 2*AC.MaxIf;
1056 newheap = (LONG *)Malloc1(sizeof(LONG)*(newmax+1),"IfHeap");
1057 newsumcheck = (WORD *)Malloc1(sizeof(WORD)*(newmax+1),"IfSumCheck");
1058 newifcount = (LONG *)Malloc1(sizeof(LONG)*(newmax+1),"IfCount");
1059 if ( AC.MaxIf ) {
1060 for ( i = 0; i < AC.MaxIf; i++ ) {
1061 newheap[i] = AC.IfHeap[i];
1062 newsumcheck[i] = AC.IfSumCheck[i];
1063 newifcount[i] = AC.IfCount[i];
1064 }
1065 AC.IfStack = (AC.IfStack-AC.IfHeap) + newheap;
1066 M_free(AC.IfHeap,"AC.IfHeap");
1067 M_free(AC.IfCount,"AC.IfCount");
1068 M_free(AC.IfSumCheck,"AC.IfSumCheck");
1069 }
1070 else {
1071 AC.IfStack = newheap;
1072 }
1073 AC.IfHeap = newheap;
1074 AC.IfSumCheck = newsumcheck;
1075 AC.IfCount = newifcount;
1076 AC.MaxIf = newmax;
1077}
1078
1079/*
1080 #] DoubleIfBuffers :
1081 #] If statement :
1082 #[ Switch statement :
1083 #[ DoSwitch :
1084*/
1085
1086int DoSwitch(PHEAD WORD *term, WORD *lhs)
1087{
1088/*
1089 For the moment we ignore the compiler buffer problems.
1090*/
1091 WORD numdollar = lhs[2];
1092 WORD ncase = DolToNumber(BHEAD numdollar);
1093 SWITCHTABLE *swtab = FindCase(lhs[3],ncase);
1094 return(Generator(BHEAD term,swtab->value));
1095}
1096
1097/*
1098 #] DoSwitch :
1099 #[ DoEndSwitch :
1100*/
1101
1102int DoEndSwitch(PHEAD WORD *term, WORD *lhs)
1103{
1104 SWITCH *sw = AC.SwitchArray+lhs[2];
1105 return(Generator(BHEAD term,sw->endswitch.value+1));
1106}
1107
1108/*
1109 #] DoEndSwitch :
1110 #[ FindCase :
1111*/
1112
1113SWITCHTABLE *FindCase(WORD nswitch, WORD ncase)
1114{
1115/*
1116 First find the switch table and determine how we have to search.
1117*/
1118 SWITCH *sw = AC.SwitchArray+nswitch;
1119 WORD hi, lo, med;
1120 if ( sw->typetable == DENSETABLE ) {
1121 med = ncase - sw->caseoffset;
1122 if ( med >= sw->numcases || med < 0 ) return(&sw->defaultcase);
1123 }
1124 else {
1125/*
1126 We need a binary search in the table.
1127*/
1128 if ( ncase > sw->maxcase || ncase < sw->mincase ) return(&sw->defaultcase);
1129 hi = sw->numcases-1; lo = 0;
1130 for(;;) {
1131 med = (hi+lo)/2;
1132 if ( ncase == sw->table[med].ncase ) break;
1133 else if ( ncase > sw->table[med].ncase ) {
1134 lo = med+1;
1135 if ( lo > hi ) return(&sw->defaultcase);
1136 }
1137 else {
1138 hi = med-1;
1139 if ( hi < lo ) return(&sw->defaultcase);
1140 }
1141 }
1142 }
1143 return(&sw->table[med]);
1144}
1145
1146/*
1147 #] FindCase :
1148 #[ DoubleSwitchBuffers :
1149*/
1150
1151int DoubleSwitchBuffers(void)
1152{
1153 int newmax, i;
1154 SWITCH *newarray;
1155 WORD *newheap;
1156 if ( AC.MaxSwitch == 0 ) newmax = 10;
1157 else newmax = 2*AC.MaxSwitch;
1158 newarray = (SWITCH *)Malloc1(sizeof(SWITCH)*(newmax+1),"SwitchArray");
1159 newheap = (WORD *)Malloc1(sizeof(WORD)*(newmax+1),"SwitchHeap");
1160 if ( AC.MaxSwitch ) {
1161 for ( i = 0; i < AC.MaxSwitch; i++ ) {
1162 newarray[i] = AC.SwitchArray[i];
1163 newheap[i] = AC.SwitchHeap[i];
1164 }
1165 M_free(AC.SwitchHeap,"AC.SwitchHeap");
1166 M_free(AC.SwitchArray,"AC.SwitchArray");
1167 }
1168 for ( i = AC.MaxSwitch; i <= newmax; i++ ) {
1169 newarray[i].table = 0;
1170 newarray[i].tablesize = 0;
1171 newarray[i].defaultcase.ncase = 0;
1172 newarray[i].defaultcase.value = 0;
1173 newarray[i].defaultcase.compbuffer = 0;
1174 newarray[i].endswitch.ncase = 0;
1175 newarray[i].endswitch.value = 0;
1176 newarray[i].endswitch.compbuffer = 0;
1177 newarray[i].typetable = 0;
1178 newarray[i].mincase = 0;
1179 newarray[i].maxcase = 0;
1180 newarray[i].numcases = 0;
1181 newarray[i].caseoffset = 0;
1182 newarray[i].iflevel = 0;
1183 newarray[i].whilelevel = 0;
1184 newarray[i].nestingsum = 0;
1185 newheap[i] = 0;
1186 }
1187 AC.SwitchArray = newarray;
1188 AC.SwitchHeap = newheap;
1189 AC.MaxSwitch = newmax;
1190 return(0);
1191}
1192
1193/*
1194 #] DoubleSwitchBuffers :
1195 #[ SwitchSplitMerge :
1196
1197 Sorts an array of WORDs. No adding of equal objects.
1198*/
1199
1200void SwitchSplitMergeRec(SWITCHTABLE *array,WORD num,SWITCHTABLE *auxarray)
1201{
1202 WORD n1,n2,i,j,k;
1203 SWITCHTABLE *t1,*t2, t;
1204 if ( num < 2 ) return;
1205 if ( num == 2 ) {
1206 if ( array[0].ncase > array[1].ncase ) {
1207 t = array[0]; array[0] = array[1]; array[1] = t;
1208 }
1209 return;
1210 }
1211 n1 = num/2;
1212 n2 = num - n1;
1213 SwitchSplitMergeRec(array,n1,auxarray);
1214 SwitchSplitMergeRec(array+n1,n2,auxarray);
1215 if ( array[n1-1].ncase <= array[n1].ncase ) return;
1216
1217 t1 = array; t2 = auxarray; i = n1; NCOPY(t2,t1,i);
1218 i = 0; j = n1; k = 0;
1219 while ( i < n1 && j < num ) {
1220 if ( auxarray[i].ncase <= array[j].ncase ) { array[k++] = auxarray[i++]; }
1221 else { array[k++] = array[j++]; }
1222 }
1223 while ( i < n1 ) array[k++] = auxarray[i++];
1224/*
1225 Remember: remnants of j are still in place!
1226*/
1227}
1228
1229void SwitchSplitMerge(SWITCHTABLE *array,WORD num)
1230{
1231 SWITCHTABLE *auxarray = (SWITCHTABLE *)Malloc1(sizeof(SWITCHTABLE)*num/2,"SwitchSplitMerge");
1232 SwitchSplitMergeRec(array,num,auxarray);
1233 M_free(auxarray,"SwitchSplitMerge");
1234}
1235
1236/*
1237 #] SwitchSplitMerge :
1238 #] Switch statement :
1239*/
LONG EndSort(PHEAD WORD *, int)
Definition sort.c:486
int Generator(PHEAD WORD *, WORD)
Definition proces.c:3255
void LowerSortLevel(void)
Definition sort.c:4703
int NewSort(PHEAD0)
Definition sort.c:395