FORM v5.0.0-35-g6318119
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 ( dtype == MODLOCAL ) {
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 case IFFLOATNUMBER:
411/*
412 The sloppy solution is: Convert to rational.
413 This way we can write it over coef2,ncoef2
414*/
415 ncoef2 = FloatFunToRat(BHEAD coef2,ifp);
416 break;
417#endif
418 case MATCH:
419 case TYPEIF:
420 coef2[0] = HowMany(BHEAD ifp,term);
421 coef2[1] = 1;
422 if ( coef2[0] == 0 ) ncoef2 = 0;
423 break;
424 case TYPECOUNT:
425 acoef = CountDo(term,ifp);
426 coef2[0] = ABS(acoef);
427 coef2[1] = 1;
428 if ( acoef == 0 ) ncoef2 = 0;
429 else if ( acoef < 0 ) ncoef2 = -1;
430 break;
431 case TYPEFINDLOOP:
432 acoef = Lus(term,ifp[3],ifp[4],ifp[5],ifp[6],ifp[2]);
433 coef2[0] = ABS(acoef);
434 coef2[1] = 1;
435 if ( acoef == 0 ) ncoef2 = 0;
436 else if ( acoef < 0 ) ncoef2 = -1;
437 break;
438 case COEFFI:
439 r = term + *term;
440 ncoef2 = r[-1];
441 i = ABS(ncoef2);
442 cc = (UWORD *)(r - i);
443 if ( ncoef2 < 0 ) ncoef2 = (ncoef2+1)>>1;
444 else ncoef2 = (ncoef2-1)>>1;
445 i--; for ( j = 0; j < i; j++ ) coef2[j] = cc[j];
446 break;
447 case SUBEXPR:
448 ncoef2 = coef2[0] = DoIfStatement(BHEAD ifp,term);
449 coef2[1] = 1;
450 break;
451 case MULTIPLEOF:
452 ncoef2 = 1;
453 coef2[0] = ifp[2];
454 coef2[1] = 1;
455 ismul2 = 1;
456 break;
457 case IFDOLLAREXTRA:
458 break;
459 case IFDOLLAR:
460 {
461/*
462 We need to abstract a long rational in coef2
463 with length ncoef2. What if that cannot be done?
464*/
465 DOLLARS d = Dollars + ifp[2];
466#ifdef WITHPTHREADS
467 int nummodopt, dtype = -1;
468 if ( AS.MultiThreaded ) {
469 for ( nummodopt = 0; nummodopt < NumModOptdollars; nummodopt++ ) {
470 if ( ifp[2] == ModOptdollars[nummodopt].number ) break;
471 }
472 if ( nummodopt < NumModOptdollars ) {
473 dtype = ModOptdollars[nummodopt].type;
474 if ( dtype == MODLOCAL ) {
475 d = ModOptdollars[nummodopt].dstruct+AT.identity;
476 }
477 else {
478 LOCK(d->pthreadslock);
479 }
480 }
481 }
482#endif
483/*
484 We have to pick up the IFDOLLAREXTRA pieces for [1], [$y] etc.
485*/
486 if ( ifp+3 < ifstop && ifp[3] == IFDOLLAREXTRA ) {
487 if ( d->nfactors == 0 ) {
488 MLOCK(ErrorMessageLock);
489 MesPrint("Attempt to use a factor of an unfactored $-variable");
490 MUNLOCK(ErrorMessageLock);
491 Terminate(-1);
492 } {
493 WORD num = GetIfDollarNum(ifp+3,ifstop);
494 WORD *w;
495 while ( ifp+3 < ifstop && ifp[3] == IFDOLLAREXTRA ) ifp += 3;
496 if ( num > d->nfactors ) {
497 MLOCK(ErrorMessageLock);
498 MesPrint("Dollar factor number %s out of range",num);
499 MUNLOCK(ErrorMessageLock);
500 Terminate(-1);
501 }
502 if ( num == 0 ) {
503 ncoef2 = 1; coef2[0] = d->nfactors; coef2[1] = 1;
504 break;
505 }
506 w = d->factors[num-1].where;
507 if ( w == 0 ) {
508 if ( d->factors[num-1].value < 0 ) {
509 ncoef2 = -1; coef2[0] = -d->factors[num-1].value; coef2[1] = 1;
510 }
511 else {
512 ncoef2 = 1; coef2[0] = d->factors[num-1].value; coef2[1] = 1;
513 }
514 break;
515 }
516 if ( w[*w] == 0 ) {
517 r = w + *w - 1;
518 i = ABS(*r);
519 if ( i == ( *w-1 ) ) {
520 ncoef2 = (i-1)/2;
521 if ( *r < 0 ) ncoef2 = -ncoef2;
522 i--; cc = coef2; r = w + 1;
523 while ( --i >= 0 ) *cc++ = (UWORD)(*r++);
524 break;
525 }
526 }
527 goto generic;
528 }
529 }
530 else {
531 switch ( d->type ) {
532 case DOLUNDEFINED:
533 if ( AC.UnsureDollarMode == 0 ) {
534#ifdef WITHPTHREADS
535 if ( dtype > 0 && dtype != MODLOCAL ) { UNLOCK(d->pthreadslock); }
536#endif
537 MLOCK(ErrorMessageLock);
538 MesPrint("$%s is undefined",AC.dollarnames->namebuffer+d->name);
539 MUNLOCK(ErrorMessageLock);
540 Terminate(-1);
541 }
542 ncoef2 = 0; coef2[0] = 0; coef2[1] = 1;
543 break;
544 case DOLZERO:
545 ncoef2 = coef2[0] = 0; coef2[1] = 1;
546 break;
547 case DOLSUBTERM:
548 if ( d->where[0] != INDEX || d->where[1] != 3
549 || d->where[2] < 0 || d->where[2] >= AM.OffsetIndex ) {
550 if ( AC.UnsureDollarMode == 0 ) {
551#ifdef WITHPTHREADS
552 if ( dtype > 0 && dtype != MODLOCAL ) { UNLOCK(d->pthreadslock); }
553#endif
554 MLOCK(ErrorMessageLock);
555 MesPrint("$%s is of wrong type",AC.dollarnames->namebuffer+d->name);
556 MUNLOCK(ErrorMessageLock);
557 Terminate(-1);
558 }
559 ncoef2 = 0; coef2[0] = 0; coef2[1] = 1;
560 break;
561 }
562 d->index = d->where[2];
563 /* fall through */
564 case DOLINDEX:
565 if ( d->index == 0 ) {
566 ncoef2 = coef2[0] = 0; coef2[1] = 1;
567 }
568 else if ( d->index > 0 && d->index < AM.OffsetIndex ) {
569 ncoef2 = 1; coef2[0] = d->index; coef2[1] = 1;
570 }
571 else if ( AC.UnsureDollarMode == 0 ) {
572#ifdef WITHPTHREADS
573 if ( dtype > 0 && dtype != MODLOCAL ) { UNLOCK(d->pthreadslock); }
574#endif
575 MLOCK(ErrorMessageLock);
576 MesPrint("$%s is of wrong type",AC.dollarnames->namebuffer+d->name);
577 MUNLOCK(ErrorMessageLock);
578 Terminate(-1);
579 }
580 ncoef2 = coef2[0] = 0; coef2[1] = 1;
581 break;
582 case DOLWILDARGS:
583 if ( d->where[0] <= -FUNCTION ||
584 ( d->where[0] < 0 && d->where[2] != 0 )
585 || ( d->where[0] > 0 && d->where[d->where[0]] != 0 )
586 ) {
587 if ( AC.UnsureDollarMode == 0 ) {
588#ifdef WITHPTHREADS
589 if ( dtype > 0 && dtype != MODLOCAL ) { UNLOCK(d->pthreadslock); }
590#endif
591 MLOCK(ErrorMessageLock);
592 MesPrint("$%s is of wrong type",AC.dollarnames->namebuffer+d->name);
593 MUNLOCK(ErrorMessageLock);
594 Terminate(-1);
595 }
596 ncoef2 = coef2[0] = 0; coef2[1] = 1;
597 break;
598 }
599 /* fall through */
600 case DOLARGUMENT:
601 if ( d->where[0] == -SNUMBER ) {
602 if ( d->where[1] == 0 ) {
603 ncoef2 = coef2[0] = 0;
604 }
605 else if ( d->where[1] < 0 ) {
606 ncoef2 = -1;
607 coef2[0] = -d->where[1];
608 }
609 else {
610 ncoef2 = 1;
611 coef2[0] = d->where[1];
612 }
613 coef2[1] = 1;
614 }
615 else if ( d->where[0] == -INDEX
616 && d->where[1] >= 0 && d->where[1] < AM.OffsetIndex ) {
617 if ( d->where[1] == 0 ) {
618 ncoef2 = coef2[0] = 0; coef2[1] = 1;
619 }
620 else {
621 ncoef2 = 1; coef2[0] = d->where[1];
622 coef2[1] = 1;
623 }
624 }
625 else if ( d->where[0] > 0
626 && d->where[ARGHEAD] == (d->where[0]-ARGHEAD)
627 && ABS(d->where[d->where[0]-1]) ==
628 (d->where[0] - ARGHEAD-1) ) {
629 i = d->where[d->where[0]-1];
630 ncoef2 = (ABS(i)-1)/2;
631 if ( i < 0 ) { ncoef2 = -ncoef2; i = -i; }
632 i--; cc = coef2; r = d->where + ARGHEAD+1;
633 while ( --i >= 0 ) *cc++ = (UWORD)(*r++);
634 }
635 else {
636 if ( AC.UnsureDollarMode == 0 ) {
637#ifdef WITHPTHREADS
638 if ( dtype > 0 && dtype != MODLOCAL ) { UNLOCK(d->pthreadslock); }
639#endif
640 MLOCK(ErrorMessageLock);
641 MesPrint("$%s is of wrong type",AC.dollarnames->namebuffer+d->name);
642 MUNLOCK(ErrorMessageLock);
643 Terminate(-1);
644 }
645 ncoef2 = 0; coef2[0] = 0; coef2[1] = 1;
646 }
647 break;
648 case DOLNUMBER:
649 case DOLTERMS:
650 if ( d->where[d->where[0]] == 0 ) {
651 r = d->where + d->where[0]-1;
652 i = ABS(*r);
653 if ( i == ( d->where[0]-1 ) ) {
654 ncoef2 = (i-1)/2;
655 if ( *r < 0 ) ncoef2 = -ncoef2;
656 i--; cc = coef2; r = d->where + 1;
657 while ( --i >= 0 ) *cc++ = (UWORD)(*r++);
658 break;
659 }
660 }
661generic:;
662 if ( AC.UnsureDollarMode == 0 ) {
663#ifdef WITHPTHREADS
664 if ( dtype > 0 && dtype != MODLOCAL ) { UNLOCK(d->pthreadslock); }
665#endif
666 MLOCK(ErrorMessageLock);
667 MesPrint("$%s is of wrong type",AC.dollarnames->namebuffer+d->name);
668 MUNLOCK(ErrorMessageLock);
669 Terminate(-1);
670 }
671 ncoef2 = 0; coef2[0] = 0; coef2[1] = 1;
672 break;
673 }
674 }
675#ifdef WITHPTHREADS
676 if ( dtype > 0 && dtype != MODLOCAL ) { UNLOCK(d->pthreadslock); }
677#endif
678 }
679 break;
680 case IFEXPRESSION:
681 r = ifp+2; j = ifp[1] - 2; ncoef2 = 0;
682 while ( --j >= 0 ) {
683 if ( *r == AR.CurExpr ) { ncoef2 = 1; break; }
684 r++;
685 }
686 coef2[0] = ncoef2;
687 coef2[1] = 1;
688 break;
689 case IFISFACTORIZED:
690 r = ifp+2; j = ifp[1] - 2;
691 if ( j == 0 ) {
692 ncoef2 = 0;
693 if ( ( Expressions[AR.CurExpr].vflags & ISFACTORIZED ) != 0 ) {
694 ncoef2 = 1;
695 }
696 }
697 else {
698 ncoef2 = 1;
699 while ( --j >= 0 ) {
700 if ( ( Expressions[*r].vflags & ISFACTORIZED ) == 0 ) {
701 ncoef2 = 0;
702 break;
703 }
704 r++;
705 }
706 }
707 coef2[0] = ncoef2;
708 coef2[1] = 1;
709 break;
710 case IFOCCURS:
711 {
712 WORD *OccStop = ifp + ifp[1], *ifpp = ifp+2;
713 ncoef2 = 0;
714 while ( ifpp < OccStop ) {
715 if ( FindVar(ifpp,term) == 1 ) {
716 ncoef2 = 1; break;
717 }
718 if ( *ifpp == DOTPRODUCT ) ifp += 3;
719 else ifpp += 2;
720 }
721 coef2[0] = ncoef2;
722 coef2[1] = 1;
723 }
724 break;
725 case IFUSERFLAG:
726 {
727 ncoef2 = 0;
728 if ( ( Expressions[AR.CurExpr].uflags & (1 << ifp[2]) ) != 0 )
729 ncoef2 = 1;
730 coef2[0] = ncoef2;
731 coef2[1] = 1;
732 }
733 break;
734 default:
735 break;
736 }
737 if ( !first ) {
738 if ( ifp[-2] != ORCOND && ifp[-2] != ANDCOND ) {
739 if ( ( ifp[-2] == EQUAL || ifp[-2] == NOTEQUAL ) &&
740 ( ismul2 || ismul1 ) ) {
741 if ( ismul1 && ismul2 ) {
742 if ( coef1[0] == coef2[0] ) i = 1;
743 else i = 0;
744 }
745 else {
746 if ( ismul1 ) {
747 if ( ncoef2 )
748 Divvy(BHEAD coef2,&ncoef2,coef1,ncoef1);
749 cc = coef2; ncoef3 = ncoef2;
750 }
751 else {
752 if ( ncoef1 )
753 Divvy(BHEAD coef1,&ncoef1,coef2,ncoef2);
754 cc = coef1; ncoef3 = ncoef1;
755 }
756 if ( ncoef3 < 0 ) ncoef3 = -ncoef3;
757 if ( ncoef3 == 0 ) {
758 if ( ifp[-2] == EQUAL ) i = 1;
759 else i = 0;
760 }
761 else if ( cc[ncoef3] != 1 ) {
762 if ( ifp[-2] == EQUAL ) i = 0;
763 else i = 1;
764 }
765 else {
766 for ( j = 1; j < ncoef3; j++ ) {
767 if ( cc[ncoef3+j] != 0 ) break;
768 }
769 if ( j < ncoef3 ) {
770 if ( ifp[-2] == EQUAL ) i = 0;
771 else i = 1;
772 }
773 else if ( ifp[-2] == EQUAL ) i = 1;
774 else i = 0;
775 }
776 }
777 goto donemul;
778 }
779 else if ( AddRat(BHEAD coef1,ncoef1,coef2,-ncoef2,coef3,&ncoef3) ) {
780 NumberFree(coef3,"DoIfStatement"); NumberFree(Spac1,"DoIfStatement"); TermFree(Spac2,"DoIfStatement");
781 MesCall("DoIfStatement"); return(-1);
782 }
783 switch ( ifp[-2] ) {
784 case GREATER:
785 if ( ncoef3 > 0 ) i = 1;
786 else i = 0;
787 break;
788 case GREATEREQUAL:
789 if ( ncoef3 >= 0 ) i = 1;
790 else i = 0;
791 break;
792 case LESS:
793 if ( ncoef3 < 0 ) i = 1;
794 else i = 0;
795 break;
796 case LESSEQUAL:
797 if ( ncoef3 <= 0 ) i = 1;
798 else i = 0;
799 break;
800 case EQUAL:
801 if ( ncoef3 == 0 ) i = 1;
802 else i = 0;
803 break;
804 case NOTEQUAL:
805 if ( ncoef3 != 0 ) i = 1;
806 else i = 0;
807 break;
808 }
809donemul: if ( i ) { ncoef2 = 1; coef2 = Spac2; coef2[0] = coef2[1] = 1; }
810 else ncoef2 = 0;
811 ismul1 = ismul2 = 0;
812 }
813 }
814 else {
815 first = 0;
816 }
817 coef1 = Spac1;
818 i = 2*ABS(ncoef2);
819 for ( j = 0; j < i; j++ ) coef1[j] = coef2[j];
820 ncoef1 = ncoef2;
821SkipCond:
822 ifp += ifp[1];
823 } while ( ifp < ifstop );
824
825 NumberFree(coef3,"DoIfStatement"); NumberFree(Spac1,"DoIfStatement"); TermFree(Spac2,"DoIfStatement");
826 if ( ncoef1 ) return(1);
827 else return(0);
828}
829
830/*
831 #] DoIfStatement :
832 #[ HowMany : WORD HowMany(ifcode,term)
833
834 Returns the number of times that the pattern in ifcode
835 can be taken out from term. There is a subkey in ifcode[2];
836 The notation is identical to the lhs of an id statement.
837 Most of the code comes from TestMatch.
838*/
839
840WORD HowMany(PHEAD WORD *ifcode, WORD *term)
841{
842 GETBIDENTITY
843 WORD *m, *t, *r, *w, power, RetVal, i, topje, *newterm;
844 WORD *OldWork, *ww, *mm;
845 int *RepSto, RepVal;
846 int numdollars = 0;
847 m = ifcode + IDHEAD;
848 AN.FullProto = m;
849 AN.WildValue = w = m + SUBEXPSIZE;
850 m += m[1];
851 AN.WildStop = m;
852 OldWork = AT.WorkPointer;
853 if ( ( ifcode[4] & 1 ) != 0 ) { /* We have at least one dollar in the pattern */
854 AR.Eside = LHSIDEX;
855 ww = AT.WorkPointer; i = m[0]; mm = m;
856 NCOPY(ww,mm,i);
857 *OldWork += 3;
858 *ww++ = 1; *ww++ = 1; *ww++ = 3;
859 AT.WorkPointer = ww;
860 RepSto = AN.RepPoint;
861 RepVal = *RepSto;
862 NewSort(BHEAD0);
863 if ( Generator(BHEAD OldWork,AR.Cnumlhs) ) {
865 *RepSto = RepVal;
866 AN.RepPoint = RepSto;
867 AT.WorkPointer = OldWork;
868 return(-1);
869 }
870 AT.WorkPointer = ww;
871 if ( EndSort(BHEAD ww,0) < 0 ) {}
872 *RepSto = RepVal;
873 AN.RepPoint = RepSto;
874 if ( *ww == 0 || *(ww+*ww) != 0 ) {
875 if ( AP.lhdollarerror == 0 ) {
876 MLOCK(ErrorMessageLock);
877 MesPrint("&LHS must be one term");
878 MUNLOCK(ErrorMessageLock);
879 AP.lhdollarerror = 1;
880 }
881 AT.WorkPointer = OldWork;
882 return(-1);
883 }
884 m = ww; AT.WorkPointer = ww = m + *m;
885 if ( m[*m-1] < 0 ) { m[*m-1] = -m[*m-1]; }
886 *m -= m[*m-1];
887 AR.Eside = RHSIDE;
888 }
889 else {
890 ww = term + *term;
891 if ( AT.WorkPointer < ww ) AT.WorkPointer = ww;
892 }
893 ClearWild(BHEAD0);
894 while ( w < AN.WildStop ) {
895 if ( *w == LOADDOLLAR ) numdollars++;
896 w += w[1];
897 }
898 AN.RepFunNum = 0;
899 AN.RepFunList = AT.WorkPointer;
900 AT.WorkPointer = (WORD *)(((UBYTE *)(AT.WorkPointer)) + AM.MaxTer);
901 topje = cbuf[AT.ebufnum].numrhs;
902 if ( AT.WorkPointer >= AT.WorkTop ) {
903 MLOCK(ErrorMessageLock);
904 MesWork();
905 MUNLOCK(ErrorMessageLock);
906 return(-1);
907 }
908 AN.DisOrderFlag = ifcode[2] & SUBDISORDER;
909 switch ( ifcode[2] & (~SUBDISORDER) ) {
910 case SUBONLY :
911 /* Must be an exact match */
912 AN.UseFindOnly = 1; AN.ForFindOnly = 0;
913/*
914 Copy the term first to scratchterm. This is needed
915 because of the Substitute.
916*/
917 i = *term;
918 t = term; newterm = r = AT.WorkPointer;
919 NCOPY(r,t,i); AT.WorkPointer = r;
920 RetVal = 0;
921 if ( FindRest(BHEAD newterm,m) && ( AN.UsedOtherFind ||
922 FindOnly(BHEAD newterm,m) ) ) {
923 Substitute(BHEAD newterm,m,1);
924 if ( numdollars ) {
925 WildDollars(BHEAD (WORD *)0);
926 numdollars = 0;
927 }
928 ClearWild(BHEAD0);
929 RetVal = 1;
930 }
931 else RetVal = 0;
932 break;
933 case SUBMANY :
934/*
935 Copy the term first to scratchterm. This is needed
936 because of the Substitute.
937*/
938 i = *term;
939 t = term; newterm = r = AT.WorkPointer;
940 NCOPY(r,t,i); AT.WorkPointer = r;
941 RetVal = 0;
942 AN.UseFindOnly = 0;
943 if ( ( power = FindRest(BHEAD newterm,m) ) > 0 ) {
944 if ( ( power = FindOnce(BHEAD newterm,m) ) > 0 ) {
945 AN.UseFindOnly = 0;
946 do {
947 Substitute(BHEAD newterm,m,1);
948 if ( numdollars ) {
949 WildDollars(BHEAD (WORD *)0);
950 numdollars = 0;
951 }
952 ClearWild(BHEAD0);
953 RetVal++;
954 } while ( FindRest(BHEAD newterm,m) && (
955 AN.UsedOtherFind || FindOnce(BHEAD newterm,m) ) );
956 }
957 else if ( power < 0 ) {
958 do {
959 Substitute(BHEAD newterm,m,1);
960 if ( numdollars ) {
961 WildDollars(BHEAD (WORD *)0);
962 numdollars = 0;
963 }
964 ClearWild(BHEAD0);
965 RetVal++;
966 } while ( FindRest(BHEAD newterm,m) );
967 }
968 }
969 else if ( power < 0 ) {
970 if ( FindOnce(BHEAD newterm,m) ) {
971 do {
972 Substitute(BHEAD newterm,m,1);
973 if ( numdollars ) {
974 WildDollars(BHEAD (WORD *)0);
975 numdollars = 0;
976 }
977 ClearWild(BHEAD0);
978 } while ( FindOnce(BHEAD newterm,m) );
979 RetVal = 1;
980 }
981 }
982 break;
983 case SUBONCE :
984/*
985 Copy the term first to scratchterm. This is needed
986 because of the Substitute.
987*/
988 i = *term;
989 t = term; newterm = r = AT.WorkPointer;
990 NCOPY(r,t,i); AT.WorkPointer = r;
991 RetVal = 0;
992 AN.UseFindOnly = 0;
993 if ( FindRest(BHEAD newterm,m) && ( AN.UsedOtherFind || FindOnce(BHEAD newterm,m) ) ) {
994 Substitute(BHEAD newterm,m,1);
995 if ( numdollars ) {
996 WildDollars(BHEAD (WORD *)0);
997 numdollars = 0;
998 }
999 ClearWild(BHEAD0);
1000 RetVal = 1;
1001 }
1002 else RetVal = 0;
1003 break;
1004 case SUBMULTI :
1005 RetVal = FindMulti(BHEAD term,m);
1006 break;
1007 case SUBVECTOR :
1008 RetVal = 0;
1009 for ( i = 0; i < *term; i++ ) ww[i] = term[i];
1010 while ( ( power = FindAll(BHEAD ww,m,AR.Cnumlhs,ifcode) ) != 0 ) { RetVal += power; }
1011 break;
1012 case SUBSELECT :
1013 ifcode += IDHEAD; ifcode += ifcode[1]; ifcode += *ifcode;
1014 AN.UseFindOnly = 1; AN.ForFindOnly = ifcode;
1015 if ( FindRest(BHEAD term,m) && ( AN.UsedOtherFind ||
1016 FindOnly(BHEAD term,m) ) ) RetVal = 1;
1017 else RetVal = 0;
1018 break;
1019 default :
1020 RetVal = 0;
1021 break;
1022 }
1023 AT.WorkPointer = AN.RepFunList;
1024 cbuf[AT.ebufnum].numrhs = topje;
1025 return(RetVal);
1026}
1027
1028/*
1029 #] HowMany :
1030 #[ DoubleIfBuffers :
1031*/
1032
1033void DoubleIfBuffers(void)
1034{
1035 int newmax, i;
1036 WORD *newsumcheck;
1037 LONG *newheap, *newifcount;
1038 if ( AC.MaxIf == 0 ) newmax = 10;
1039 else newmax = 2*AC.MaxIf;
1040 newheap = (LONG *)Malloc1(sizeof(LONG)*(newmax+1),"IfHeap");
1041 newsumcheck = (WORD *)Malloc1(sizeof(WORD)*(newmax+1),"IfSumCheck");
1042 newifcount = (LONG *)Malloc1(sizeof(LONG)*(newmax+1),"IfCount");
1043 if ( AC.MaxIf ) {
1044 for ( i = 0; i < AC.MaxIf; i++ ) {
1045 newheap[i] = AC.IfHeap[i];
1046 newsumcheck[i] = AC.IfSumCheck[i];
1047 newifcount[i] = AC.IfCount[i];
1048 }
1049 AC.IfStack = (AC.IfStack-AC.IfHeap) + newheap;
1050 M_free(AC.IfHeap,"AC.IfHeap");
1051 M_free(AC.IfCount,"AC.IfCount");
1052 M_free(AC.IfSumCheck,"AC.IfSumCheck");
1053 }
1054 else {
1055 AC.IfStack = newheap;
1056 }
1057 AC.IfHeap = newheap;
1058 AC.IfSumCheck = newsumcheck;
1059 AC.IfCount = newifcount;
1060 AC.MaxIf = newmax;
1061}
1062
1063/*
1064 #] DoubleIfBuffers :
1065 #] If statement :
1066 #[ Switch statement :
1067 #[ DoSwitch :
1068*/
1069
1070int DoSwitch(PHEAD WORD *term, WORD *lhs)
1071{
1072/*
1073 For the moment we ignore the compiler buffer problems.
1074*/
1075 WORD numdollar = lhs[2];
1076 WORD ncase = DolToNumber(BHEAD numdollar);
1077 SWITCHTABLE *swtab = FindCase(lhs[3],ncase);
1078 return(Generator(BHEAD term,swtab->value));
1079}
1080
1081/*
1082 #] DoSwitch :
1083 #[ DoEndSwitch :
1084*/
1085
1086int DoEndSwitch(PHEAD WORD *term, WORD *lhs)
1087{
1088 SWITCH *sw = AC.SwitchArray+lhs[2];
1089 return(Generator(BHEAD term,sw->endswitch.value+1));
1090}
1091
1092/*
1093 #] DoEndSwitch :
1094 #[ FindCase :
1095*/
1096
1097SWITCHTABLE *FindCase(WORD nswitch, WORD ncase)
1098{
1099/*
1100 First find the switch table and determine how we have to search.
1101*/
1102 SWITCH *sw = AC.SwitchArray+nswitch;
1103 WORD hi, lo, med;
1104 if ( sw->typetable == DENSETABLE ) {
1105 med = ncase - sw->caseoffset;
1106 if ( med >= sw->numcases || med < 0 ) return(&sw->defaultcase);
1107 }
1108 else {
1109/*
1110 We need a binary search in the table.
1111*/
1112 if ( ncase > sw->maxcase || ncase < sw->mincase ) return(&sw->defaultcase);
1113 hi = sw->numcases-1; lo = 0;
1114 for(;;) {
1115 med = (hi+lo)/2;
1116 if ( ncase == sw->table[med].ncase ) break;
1117 else if ( ncase > sw->table[med].ncase ) {
1118 lo = med+1;
1119 if ( lo > hi ) return(&sw->defaultcase);
1120 }
1121 else {
1122 hi = med-1;
1123 if ( hi < lo ) return(&sw->defaultcase);
1124 }
1125 }
1126 }
1127 return(&sw->table[med]);
1128}
1129
1130/*
1131 #] FindCase :
1132 #[ DoubleSwitchBuffers :
1133*/
1134
1135int DoubleSwitchBuffers(void)
1136{
1137 int newmax, i;
1138 SWITCH *newarray;
1139 WORD *newheap;
1140 if ( AC.MaxSwitch == 0 ) newmax = 10;
1141 else newmax = 2*AC.MaxSwitch;
1142 newarray = (SWITCH *)Malloc1(sizeof(SWITCH)*(newmax+1),"SwitchArray");
1143 newheap = (WORD *)Malloc1(sizeof(WORD)*(newmax+1),"SwitchHeap");
1144 if ( AC.MaxSwitch ) {
1145 for ( i = 0; i < AC.MaxSwitch; i++ ) {
1146 newarray[i] = AC.SwitchArray[i];
1147 newheap[i] = AC.SwitchHeap[i];
1148 }
1149 M_free(AC.SwitchHeap,"AC.SwitchHeap");
1150 M_free(AC.SwitchArray,"AC.SwitchArray");
1151 }
1152 for ( i = AC.MaxSwitch; i <= newmax; i++ ) {
1153 newarray[i].table = 0;
1154 newarray[i].tablesize = 0;
1155 newarray[i].defaultcase.ncase = 0;
1156 newarray[i].defaultcase.value = 0;
1157 newarray[i].defaultcase.compbuffer = 0;
1158 newarray[i].endswitch.ncase = 0;
1159 newarray[i].endswitch.value = 0;
1160 newarray[i].endswitch.compbuffer = 0;
1161 newarray[i].typetable = 0;
1162 newarray[i].mincase = 0;
1163 newarray[i].maxcase = 0;
1164 newarray[i].numcases = 0;
1165 newarray[i].caseoffset = 0;
1166 newarray[i].iflevel = 0;
1167 newarray[i].whilelevel = 0;
1168 newarray[i].nestingsum = 0;
1169 newheap[i] = 0;
1170 }
1171 AC.SwitchArray = newarray;
1172 AC.SwitchHeap = newheap;
1173 AC.MaxSwitch = newmax;
1174 return(0);
1175}
1176
1177/*
1178 #] DoubleSwitchBuffers :
1179 #[ SwitchSplitMerge :
1180
1181 Sorts an array of WORDs. No adding of equal objects.
1182*/
1183
1184void SwitchSplitMergeRec(SWITCHTABLE *array,WORD num,SWITCHTABLE *auxarray)
1185{
1186 WORD n1,n2,i,j,k;
1187 SWITCHTABLE *t1,*t2, t;
1188 if ( num < 2 ) return;
1189 if ( num == 2 ) {
1190 if ( array[0].ncase > array[1].ncase ) {
1191 t = array[0]; array[0] = array[1]; array[1] = t;
1192 }
1193 return;
1194 }
1195 n1 = num/2;
1196 n2 = num - n1;
1197 SwitchSplitMergeRec(array,n1,auxarray);
1198 SwitchSplitMergeRec(array+n1,n2,auxarray);
1199 if ( array[n1-1].ncase <= array[n1].ncase ) return;
1200
1201 t1 = array; t2 = auxarray; i = n1; NCOPY(t2,t1,i);
1202 i = 0; j = n1; k = 0;
1203 while ( i < n1 && j < num ) {
1204 if ( auxarray[i].ncase <= array[j].ncase ) { array[k++] = auxarray[i++]; }
1205 else { array[k++] = array[j++]; }
1206 }
1207 while ( i < n1 ) array[k++] = auxarray[i++];
1208/*
1209 Remember: remnants of j are still in place!
1210*/
1211}
1212
1213void SwitchSplitMerge(SWITCHTABLE *array,WORD num)
1214{
1215 SWITCHTABLE *auxarray = (SWITCHTABLE *)Malloc1(sizeof(SWITCHTABLE)*num/2,"SwitchSplitMerge");
1216 SwitchSplitMergeRec(array,num,auxarray);
1217 M_free(auxarray,"SwitchSplitMerge");
1218}
1219
1220/*
1221 #] SwitchSplitMerge :
1222 #] Switch statement :
1223*/
LONG EndSort(PHEAD WORD *, int)
Definition sort.c:454
int Generator(PHEAD WORD *, WORD)
Definition proces.c:3249
void LowerSortLevel(void)
Definition sort.c:4661
int NewSort(PHEAD0)
Definition sort.c:359