• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tueda / form / 15241916852

25 May 2025 08:59PM UTC coverage: 47.908% (-2.8%) from 50.743%
15241916852

push

github

tueda
ci: build arm64-windows binaries

39009 of 81425 relevant lines covered (47.91%)

1079780.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

33.47
/sources/transform.c
1
/** @file transform.c
2
 * 
3
 *        Routines that deal with the transform statement and its varieties.
4
 */
5
/* #[ License : */
6
/*
7
 *   Copyright (C) 1984-2023 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 : transform.c
33
*/
34

35
#include "form3.h"
36

37
/*
38
          #] Includes : 
39
         #[ Transform :
40
                 #[ Intro :
41

42
                Here are the routines for the transform statement. This is a 
43
                group of transformations on function arguments or groups of
44
                function arguments. The purpose of this command is that it
45
                avoids repetitive pattern matching.
46
                Syntax:
47
                        Transform,SetOfFunctions,OneOrMoreTransformations;
48
                Each transformation is given by
49
                        Replace(argfirst,arglast)=(,,,)
50
                        Encode(argfirst,arglast):base=#
51
                        Decode(argfirst,arglast):base=#
52
                        Implode(argfirst,arglast)
53
                        Explode(argfirst,arglast)
54
                        Permute(cycle)(cycle)(cycle)...(cycle)
55
                        Reverse(argfirst,arglast)
56
                        Dedup(argfirst,arglast)
57
                        Cycle(argfirst,arglast)=+/-num
58
                        IsLyndon(argfirst,arglast)=(yes,no)
59
                        ToLyndon(argfirst,arglast)=(yes,no)
60
                In replace the extra information is
61
                        a replace_() without the name of the replace_ function.
62
                        This can be as in (0,1,1,0) or (xarg_,1-xarg_) to indicate
63
                        a symbolic argument or (x,y,y,x) to exchange x and y, etc.
64
                In Encode and Decode argfirst is the most significant 'word' and
65
                arglast is the least significant 'word'.
66
                Note that we need to introduce the generic symbolic arguments xarg_,
67
                parg_, iarg_ and farg_.
68
                Examples:
69
                        Transform,{H,E}
70
                                        ,Replace(1:`WEIGHT')=(0,1,1,0)
71
                                        ,Encode(1:`WEIGHT')=base(2);
72
                        Transform,{H,E}
73
                                        ,Decode(1:`WEIGHT')=base(3)
74
                                        ,Replace(1:`WEIGHT')=(2,-1,1,0,0,1);
75
                Others that can be added:
76
                        symmetrize?
77

78
                6-may-2016: Changed MAXPOSITIVE2 into MAXPOSITIVE4. This makes room
79
                            for the use of dollar variables as arguments.
80

81
                 #] Intro : 
82
                 #[ CoTransform :
83
*/
84

85
static WORD tranarray[10] = { SUBEXPRESSION, SUBEXPSIZE, 0, 1, 0, 0, 0, 0, 0, 0 };
86

87
int CoTransform(UBYTE *in)
138✔
88
{
89
        GETIDENTITY
92✔
90
        UBYTE *s = in, c, *ss, *Tempbuf;
138✔
91
        WORD number, type, i, *work = AT.WorkPointer+2, *wp, range[2], one = 1;
138✔
92
        WORD numdol, *wstart;
138✔
93
        int error = 0, irhs;
138✔
94
        LONG x;
138✔
95
        while ( *in == ',' ) in++;
138✔
96
        wp = work + 1;
138✔
97
/*
98
          #[ Sets :
99

100
        First the set specification(s). No sets means all functions (dangerous!)
101
*/
102
        for(;;) {
276✔
103
                if ( *in == '{' ) {
276✔
104
                        s = in+1;
×
105
                        SKIPBRA2(in)
×
106
                        number = DoTempSet(s,in);
×
107
                        in++;
×
108
                        if ( *in != ',' ) {
×
109
                                c = in[1]; in[1] = 0;
×
110
                                MesPrint("& %s: A set in a transform statement should be followed by a comma",s);
×
111
                                in[1] = c; in++;
×
112
                                if ( error == 0 ) error = 1;
×
113
                        }
114
                }
115
                else if ( *in == '[' || FG.cTable[*in] == 0 ) {
276✔
116
                        s = in;
276✔
117
                        in = SkipAName(in);
276✔
118
                        if ( *in != ',' ) break;
276✔
119
                        c = *in; *in = 0;
138✔
120
                    type = GetName(AC.varnames,s,&number,NOAUTO);
138✔
121
                        if ( type == CFUNCTION ) { number += MAXVARIABLES + FUNCTION; }
138✔
122
                        else if ( type != CSET ) {
×
123
                                MesPrint("& %s: A transform statement starts with sets of functions",s);
×
124
                                if ( error == 0 ) error = 1;
×
125
                        }
126
                        *in++ = c;
138✔
127
                }
128
                else {
129
                        MesPrint("&Illegal syntax in Transform statement",s);
×
130
                        if ( error == 0 ) error = 1;
×
131
                        return(error);
×
132
                }
133
                if ( number >= 0 ) {
138✔
134
                  if ( number < MAXVARIABLES ) {
138✔
135
/*
136
                        Check that this is a set of functions
137
*/
138
                        if ( Sets[number].type != CFUNCTION ) {
×
139
                                MesPrint("&A set in a transform statement should be a set of functions");
×
140
                                if ( error == 0 ) error = 1;
×
141
                        }
142
                  }
143
                }
144
                else if ( error == 0 ) error = 1;
×
145
/*
146
                Now write the number to the right place
147
*/
148
                *wp++ = number;
138✔
149
                while ( *in == ',' ) in++;
138✔
150
        }
151
        *work = wp - work;
138✔
152
        work = wp; wp++;
138✔
153
/*
154
          #] Sets : 
155

156
        Now we should loop over the various transformations
157
*/
158
        while ( *s ) {
282✔
159
                in = s;
144✔
160
                if ( FG.cTable[*in] != 0 ) {
144✔
161
                        MesPrint("&Illegal character in Transform statement");
×
162
                        if ( error == 0 ) error = 1;
×
163
                        return(error);
×
164
                }
165
                in = SkipAName(in);
144✔
166
                if ( *in == '>' || *in == '<' ) in++;
144✔
167
                ss = in;
144✔
168
                c = *ss; *ss = 0;
144✔
169
                if ( c != '(' ) {
144✔
170
                        MesPrint("&Illegal syntax in specifying a transformation inside a Transform statement");
×
171
                        if ( error == 0 ) error = 1;
×
172
                        return(error);
×
173
                }
174
/*
175
                 #[ replace :
176
*/
177
                if ( StrICmp(s,(UBYTE *)"replace") == 0 ) {
144✔
178
/*
179
                                Subkeys: (,,,) as in replace_(,,,)
180
                        The idea here is to read the subkeys as the argument
181
                        of a replace_ function.
182
                        We put the whole together as in the multiply statement (which
183
                        could just be a replace_(....)) and compile it.
184
                        Then we expand the tree with Generator and check the complete
185
                        expression for legality.
186
*/
187
                        type = REPLACEARG;
188
doreplace:
9✔
189
                        *ss = c;
9✔
190
                        if ( ( in = ReadRange(in,range,0) ) == 0 ) {
9✔
191
                                if ( error == 0 ) error = 1;
×
192
                                return(error);
×
193
                        }
194
                        in++;
9✔
195
/*
196
                        We have replace(#,#)=(...), and we want dum_(...)  (DUMFUN)
197
                        to send to the compiler. The pointer is after the '=';
198
*/
199
                        s = in;
9✔
200
                        if ( *s != '(' ) {
9✔
201
                                MesPrint("&");
×
202
                                if ( error == 0 ) error = 1;
×
203
                                return(error);
×
204
                        }
205
                        SKIPBRA3(in);
120✔
206
                        if ( *in != ')' ) {
9✔
207
                                MesPrint("&");
×
208
                                if ( error == 0 ) error = 1;
×
209
                                return(error);
×
210
                        }
211
                        in++;
9✔
212
                        if ( *in != ',' && *in != '\0' ) {
9✔
213
                                MesPrint("&");
×
214
                                if ( error == 0 ) error = 1;
×
215
                                return(error);
×
216
                        }
217
                        i = in - s;
9✔
218
                        ss = Tempbuf = (UBYTE *)Malloc1(i+5,"CoTransform/replace");
9✔
219
                        *ss++ = 'd'; *ss++ = 'u'; *ss++ = 'm'; *ss++ = '_';
9✔
220
                        NCOPY(ss,s,i)
138✔
221
                        *ss++ = 0;
9✔
222
                        AC.ProtoType = tranarray;
9✔
223
                        tranarray[4] = AC.cbufnum;
9✔
224
                        irhs = CompileAlgebra(Tempbuf,RHSIDE,AC.ProtoType);
9✔
225
                        M_free(Tempbuf,"CoTransform/replace");
9✔
226
                        if ( irhs < 0 ) {
9✔
227
                                if ( error == 0 ) error = 1;
×
228
                                return(error);
×
229
                        }
230
                        tranarray[2] = irhs;
9✔
231
/*
232
                        The result of the compilation goes through Generator during
233
                        execution, because that takes care of $-variables.
234
                        This is why we could not use replace_ and had to use dum_.
235
*/
236
                        *wp++ = ARGRANGE;
9✔
237
                        *wp++ = range[0];
9✔
238
                        *wp++ = range[1];
9✔
239
                        *wp++ = type;
9✔
240
                        *wp++ = SUBEXPSIZE+4;
9✔
241
                        for ( i = 0; i < SUBEXPSIZE; i++ ) *wp++ = tranarray[i];
54✔
242
                        *wp++ = 1;
9✔
243
                        *wp++ = 1;
9✔
244
                        *wp++ = 3;
9✔
245
                        *work = wp-work;
9✔
246
                        work = wp; *wp++ = 0;
9✔
247
                        s = in;
9✔
248
                }
249
/*
250
                 #] replace : 
251
                 #[ encode/decode :
252
*/
253
                else if ( StrICmp(s,(UBYTE *)"decode" ) == 0 ) {
135✔
254
                        type = DECODEARG;
×
255
                        goto doencode;
×
256
                }
257
                else if ( StrICmp(s,(UBYTE *)"encode" ) == 0 ) {
135✔
258
                        type = ENCODEARG;
259
doencode:        *ss = c;
3✔
260
                        if ( ( in = ReadRange(in,range,2) ) == 0 ) {
3✔
261
                                if ( error == 0 ) error = 1;
×
262
                                return(error);
×
263
                        }
264
                        in++;
3✔
265
                        s = in; while ( FG.cTable[*in] == 0 ) in++;
15✔
266
                        c = *in; *in = 0;
3✔
267
/*
268
                                Subkeys: base=# or base=$var
269
*/
270
                        if ( StrICmp(s,(UBYTE *)"base") == 0 ) {
3✔
271
                                *in = c;
3✔
272
                                if ( *in != '=' ) {
3✔
273
                                        MesPrint("&Illegal base specification in encode/decode transformation");
×
274
                                        if ( error == 0 ) error = 1;
×
275
                                        return(error);
×
276
                                }
277
                                in++;
3✔
278
                                if ( *in == '$' ) {
3✔
279
                                        in++; ss = in;
×
280
                                        in = SkipAName(in);
×
281
                                        c = *in; *in = 0;
×
282
                                        if ( GetName(AC.dollarnames,ss,&numdol,NOAUTO) != CDOLLAR ) {
×
283
                                                MesPrint("&%s is undefined",ss-1);
×
284
                                                numdol = AddDollar(ss,DOLINDEX,&one,1);
×
285
                                                return(1);
×
286
                                        }
287
                                        *in = c;
×
288
                                        x = -numdol;
×
289
                                }
290
                                else {
291
                                        x = 0;
292
                                        while ( FG.cTable[*in] == 1 ) {
6✔
293
                                                x = 10*x + *in++ - '0';
3✔
294
                                                if ( x > MAXPOSITIVE4 ) {
3✔
295
illsize:                                        MesPrint("&Illegal value for base in encode/decode transformation");
×
296
                                                        if ( error == 0 ) error = 1;
×
297
                                                        return(error);
×
298
                                                }
299
                                        }
300
                                        if ( x <= 1 ) goto illsize;
3✔
301
                                }
302
                                if ( *in != ',' && *in != '\0' ) {
3✔
303
                                        MesPrint("&Illegal termination of transformation");
×
304
                                        if ( error == 0 ) error = 1;
×
305
                                        return(error);
×
306
                                }
307
                        }
308
                        else {
309
                                MesPrint("&Illegal option in encode/decode transformation");
×
310
                                if ( error == 0 ) error = 1;
×
311
                                return(error);
×
312
                        }
313
/*
314
                        Now we can put the whole statement together
315
                        We have the set(s) in work up to wp and the range in range.
316
                        The base is in x and the type tells whether it is encode or decode.
317
*/
318
                        *wp++ = ARGRANGE;
3✔
319
                        *wp++ = range[0];
3✔
320
                        *wp++ = range[1];
3✔
321
                        *wp++ = type;
3✔
322
                        *wp++ = 4;
3✔
323
                        *wp++ = BASECODE;
3✔
324
                        *wp++ = (WORD)x;
3✔
325
                        *work = wp-work;
3✔
326
                        work = wp; *wp++ = 0;
3✔
327
                        s = in;
3✔
328
                }
329
/*
330
                 #] encode/decode : 
331
                 #[ implode :
332
*/
333
                else if ( StrICmp(s,(UBYTE *)"implode") == 0
132✔
334
                           || StrICmp(s,(UBYTE *)"tosumnotation") == 0 ) {
132✔
335
/*
336
                                Subkeys: ?
337
*/
338
                        type = IMPLODEARG;
×
339
                        *ss = c;
×
340
                        if ( ( in = ReadRange(in,range,1) ) == 0 ) {
×
341
                                if ( error == 0 ) error = 1;
×
342
                                return(error);
×
343
                        }
344
                        *wp++ = ARGRANGE;
×
345
                        *wp++ = range[0];
×
346
                        *wp++ = range[1];
×
347
                        *wp++ = type;
×
348
                        *work = wp-work;
×
349
                        work = wp; *wp++ = 0;
×
350
                        s = in;
×
351
                }
352
/*
353
                 #] implode : 
354
                 #[ explode :
355
*/
356
                else if ( StrICmp(s,(UBYTE *)"explode") == 0
132✔
357
                           || StrICmp(s,(UBYTE *)"tointegralnotation") == 0 ) {
129✔
358
/*
359
                                Subkeys: ?
360
*/
361
                        type = EXPLODEARG;
3✔
362
                        *ss = c;
3✔
363
                        if ( ( in = ReadRange(in,range,1) ) == 0 ) {
3✔
364
                                if ( error == 0 ) error = 1;
×
365
                                return(error);
×
366
                        }
367
                        *wp++ = ARGRANGE;
3✔
368
                        *wp++ = range[0];
3✔
369
                        *wp++ = range[1];
3✔
370
                        *wp++ = type;
3✔
371
                        *work = wp-work;
3✔
372
                        work = wp; *wp++ = 0;
3✔
373
                        s = in;
3✔
374
                }
375
/*
376
                 #] explode : 
377
                 #[ permute :
378
*/
379
                else if ( StrICmp(s,(UBYTE *)"permute") == 0 ) {
129✔
380
                        type = PERMUTEARG;
×
381
                        *ss = c;
×
382
                        *wp++ = ARGRANGE;
×
383
                        *wp++ = 1;
×
384
                        *wp++ = MAXPOSITIVE4;
×
385
                        *wp++ = type;
×
386
/*
387
                        Now a sequence of cycles
388
*/
389
                        do {
×
390
                          wstart = wp; wp++;
×
391
                          do {
×
392
                                in++;
×
393
                                if ( *in == '$' ) {
×
394
                                        WORD number; UBYTE *t;
×
395
                                        in++; t = in;
×
396
                                        while ( FG.cTable[*in] < 2 ) in++;
×
397
                                        c = *in; *in = 0;
×
398
                                        if ( ( number = GetDollar(t) ) < 0 ) {
×
399
                                                MesPrint("&Undefined variable $%s",t);
×
400
                                                if ( !error ) error = 1;
×
401
                                                number = AddDollar(t,0,0,0);
×
402
                                        }
403
                                        *in = c;
×
404
                                        *wp++ = -number-1;
×
405
                                }
406
                                else {
407
                                  x = 0;
408
                                  while ( FG.cTable[*in] == 1 ) {
×
409
                                        x = 10*x + *in++ - '0';
×
410
                                        if ( x > MAXPOSITIVE4 ) {
×
411
                                                MesPrint("&value in permute transformation too large");
×
412
                                                if ( error == 0 ) error = 1;
×
413
                                                return(error);
×
414
                                        }
415
                                  }
416
                                  if ( x == 0 ) {
×
417
                                        MesPrint("&value 0 in permute transformation not allowed");
×
418
                                        if ( error == 0 ) error = 1;
×
419
                                        return(error);
×
420
                                  }
421
                                  *wp++ = (WORD)x-1;
×
422
                                }
423
                          } while ( *in == ',' );
×
424
                          if ( *in != ')' ) {
×
425
                                MesPrint("&Illegal syntax in permute transformation");
×
426
                                if ( error == 0 ) error = 1;
×
427
                                return(error);
×
428
                          }
429
                          in++;
×
430
                          if ( *in != ',' && *in != '(' && *in != '\0' ) {
×
431
                                MesPrint("&Illegal ending in permute transformation");
×
432
                                if ( error == 0 ) error = 1;
×
433
                                return(error);
×
434
                          }
435
                          *wstart = wp-wstart;
×
436
                          if ( *wstart == 1 ) wstart--;
×
437
                        } while ( *in == '(' );
×
438
                        *work = wp-work;
×
439
                        work = wp; *wp++ = 0;
×
440
                        s = in;
×
441
                }
442
/*
443
                 #] permute : 
444
                 #[ reverse :
445
*/
446
                else if ( StrICmp(s,(UBYTE *)"reverse") == 0 ) {
129✔
447
                        type = REVERSEARG;
×
448
                        *ss = c;
×
449
                        if ( ( in = ReadRange(in,range,1) ) == 0 ) {
×
450
                                if ( error == 0 ) error = 1;
×
451
                                return(error);
×
452
                        }
453
                        *wp++ = ARGRANGE;
×
454
                        *wp++ = range[0];
×
455
                        *wp++ = range[1];
×
456
                        *wp++ = type;
×
457
                        *work = wp-work;
×
458
                        work = wp; *wp++ = 0;
×
459
                        s = in;
×
460
                }
461
/*
462
                 #] reverse : 
463
                 #[ dedup :
464
*/
465
                else if ( StrICmp(s,(UBYTE *)"dedup") == 0 ) {
129✔
466
                        type = DEDUPARG;
21✔
467
                        *ss = c;
21✔
468
                        if ( ( in = ReadRange(in,range,1) ) == 0 ) {
21✔
469
                                if ( error == 0 ) error = 1;
×
470
                                return(error);
×
471
                        }
472
                        *wp++ = ARGRANGE;
21✔
473
                        *wp++ = range[0];
21✔
474
                        *wp++ = range[1];
21✔
475
                        *wp++ = type;
21✔
476
                        *work = wp-work;
21✔
477
                        work = wp; *wp++ = 0;
21✔
478
                        s = in;
21✔
479
                }
480
/*
481
                 #] dedup : 
482
                 #[ cycle :
483
*/
484
                else if ( StrICmp(s,(UBYTE *)"cycle") == 0 ) {
108✔
485
                        type = CYCLEARG;
×
486
                        *ss = c;
×
487
                        if ( ( in = ReadRange(in,range,0) ) == 0 ) {
×
488
                                if ( error == 0 ) error = 1;
×
489
                                return(error);
×
490
                        }
491
                        *wp++ = ARGRANGE;
×
492
                        *wp++ = range[0];
×
493
                        *wp++ = range[1];
×
494
                        *wp++ = type;
×
495
/*
496
                        Now a sequence of cycles
497
*/
498
                        in++;
×
499
                        if ( *in == '+' ) {
×
500
                        }
501
                        else if ( *in == '-' ) {
×
502
                                one = -1;
×
503
                        }
504
                        else {
505
                                MesPrint("&Cycle in a Transform statement should be followed by =+/-number/$");
×
506
                                if ( error == 0 ) error = 1;
×
507
                                return(error);
×
508
                        }
509
                        in++; x = 0;
×
510
                        if ( *in == '$' ) {
×
511
                                UBYTE *si = in;
×
512
                                in++; si = in;
×
513
                                while ( FG.cTable[*in] == 0 || FG.cTable[*in] == 1 ) in++;
×
514
                                c = *in; *in = 0;
×
515
                                if ( ( x = GetDollar(si) ) < 0 ) {
×
516
                                        MesPrint("&Undefined $-variable in transform,cycle statement.");
×
517
                                        error = 1;
×
518
                                }
519
                                *in = c;
×
520
                                if ( one < 0 ) x += MAXPOSITIVE4;
×
521
                                x += MAXPOSITIVE2;
×
522
                                *wp++ = x;
×
523
                        }
524
                        else {
525
                          while ( FG.cTable[*in] == 1 ) {
×
526
                                x = 10*x + *in++ - '0';
×
527
                                if ( x > MAXPOSITIVE4 ) {
×
528
                                        MesPrint("&Number in cycle in a Transform statement too big");
×
529
                                        if ( error == 0 ) error = 1;
×
530
                                        return(error);
×
531
                                }
532
                          }
533
                          *wp++ = x*one;
×
534
                        }
535
                        *work = wp-work;
×
536
                        work = wp; *wp++ = 0;
×
537
                        s = in;
×
538
                }
539
/*
540
                 #] cycle : 
541
                 #[ islyndon/tolyndon :
542
*/
543
                else if ( StrICmp(s,(UBYTE *)"islyndon" ) == 0 ) {
108✔
544
                        type = ISLYNDON;
×
545
                        goto doreplace;
×
546
                }
547
                else if ( StrICmp(s,(UBYTE *)"islyndon<" ) == 0 ) {
108✔
548
                        type = ISLYNDON;
×
549
                        goto doreplace;
×
550
                }
551
                else if ( StrICmp(s,(UBYTE *)"islyndon+" ) == 0 ) {
108✔
552
                        type = ISLYNDON;
×
553
                        goto doreplace;
×
554
                }
555
                else if ( StrICmp(s,(UBYTE *)"islyndon>" ) == 0 ) {
108✔
556
                        type = ISLYNDONR;
×
557
                        goto doreplace;
×
558
                }
559
                else if ( StrICmp(s,(UBYTE *)"islyndon-" ) == 0 ) {
108✔
560
                        type = ISLYNDONR;
×
561
                        goto doreplace;
×
562
                }
563
                else if ( StrICmp(s,(UBYTE *)"tolyndon" ) == 0 ) {
108✔
564
                        type = TOLYNDON;
×
565
                        goto doreplace;
×
566
                }
567
                else if ( StrICmp(s,(UBYTE *)"tolyndon<" ) == 0 ) {
108✔
568
                        type = TOLYNDON;
×
569
                        goto doreplace;
×
570
                }
571
                else if ( StrICmp(s,(UBYTE *)"tolyndon+" ) == 0 ) {
108✔
572
                        type = TOLYNDON;
×
573
                        goto doreplace;
×
574
                }
575
                else if ( StrICmp(s,(UBYTE *)"tolyndon>" ) == 0 ) {
108✔
576
                        type = TOLYNDONR;
×
577
                        goto doreplace;
×
578
                }
579
                else if ( StrICmp(s,(UBYTE *)"tolyndon-" ) == 0 ) {
108✔
580
                        type = TOLYNDONR;
×
581
                        goto doreplace;
×
582
                }
583
/*
584
                 #] islyndon/tolyndon : 
585
                 #[ addarg :
586
*/
587
                else if ( StrICmp(s,(UBYTE *)"addargs" ) == 0 ) {
108✔
588
                        type = ADDARG;
27✔
589
                        *ss = c;
27✔
590
                        if ( ( in = ReadRange(in,range,1) ) == 0 ) {
27✔
591
                                if ( error == 0 ) error = 1;
×
592
                                return(error);
×
593
                        }
594
                        *wp++ = ARGRANGE;
27✔
595
                        *wp++ = range[0];
27✔
596
                        *wp++ = range[1];
27✔
597
                        *wp++ = type;
27✔
598
                        *work = wp-work;
27✔
599
                        work = wp; *wp++ = 0;
27✔
600
                        s = in;
27✔
601
                }
602
/*
603
                 #] addarg : 
604
                 #[ mularg :
605
*/
606
                else if ( ( StrICmp(s,(UBYTE *)"mulargs" ) == 0 )
81✔
607
                           || ( StrICmp(s,(UBYTE *)"multiplyargs" ) == 0 ) ) {
48✔
608
                        type = MULTIPLYARG;
33✔
609
                        *ss = c;
33✔
610
                        if ( ( in = ReadRange(in,range,1) ) == 0 ) {
33✔
611
                                if ( error == 0 ) error = 1;
×
612
                                return(error);
×
613
                        }
614
                        *wp++ = ARGRANGE;
33✔
615
                        *wp++ = range[0];
33✔
616
                        *wp++ = range[1];
33✔
617
                        *wp++ = type;
33✔
618
                        *work = wp-work;
33✔
619
                        work = wp; *wp++ = 0;
33✔
620
                        s = in;
33✔
621
                }
622
/*
623
                 #] mularg : 
624
                 #[ droparg :
625
*/
626
                else if ( StrICmp(s,(UBYTE *)"dropargs" ) == 0 ) {
48✔
627
                        type = DROPARG;
24✔
628
                        *ss = c;
24✔
629
                        if ( ( in = ReadRange(in,range,1) ) == 0 ) {
24✔
630
                                if ( error == 0 ) error = 1;
×
631
                                return(error);
×
632
                        }
633
                        *wp++ = ARGRANGE;
24✔
634
                        *wp++ = range[0];
24✔
635
                        *wp++ = range[1];
24✔
636
                        *wp++ = type;
24✔
637
                        *work = wp-work;
24✔
638
                        work = wp; *wp++ = 0;
24✔
639
                        s = in;
24✔
640
                }
641
/*
642
                 #] droparg : 
643
                 #[ selectarg :
644
*/
645
                else if ( StrICmp(s,(UBYTE *)"selectargs" ) == 0 ) {
24✔
646
                        type = SELECTARG;
24✔
647
                        *ss = c;
24✔
648
                        if ( ( in = ReadRange(in,range,1) ) == 0 ) {
24✔
649
                                if ( error == 0 ) error = 1;
×
650
                                return(error);
×
651
                        }
652
                        *wp++ = ARGRANGE;
24✔
653
                        *wp++ = range[0];
24✔
654
                        *wp++ = range[1];
24✔
655
                        *wp++ = type;
24✔
656
                        *work = wp-work;
24✔
657
                        work = wp; *wp++ = 0;
24✔
658
                        s = in;
24✔
659
                }
660
/*
661
                 #] selectarg : 
662
                 #[ ZtoH :
663
*/
664
                else if ( StrICmp(s,(UBYTE *)"ztoh") == 0 ) {
×
665
/*
666
                                Subkeys: ?
667
*/
668
                        type = ZTOHARG;
×
669
                        *ss = c;
×
670
                        if ( ( in = ReadRange(in,range,1) ) == 0 ) {
×
671
                                if ( error == 0 ) error = 1;
×
672
                                return(error);
×
673
                        }
674
                        *wp++ = ARGRANGE;
×
675
                        *wp++ = range[0];
×
676
                        *wp++ = range[1];
×
677
                        *wp++ = type;
×
678
                        *work = wp-work;
×
679
                        work = wp; *wp++ = 0;
×
680
                        s = in;
×
681
                }
682
/*
683
                 #] ZtoH : 
684
                 #[ HtoZ :
685
*/
686
                else if ( StrICmp(s,(UBYTE *)"htoz") == 0 ) {
×
687
/*
688
                                Subkeys: ?
689
*/
690
                        type = HTOZARG;
×
691
                        *ss = c;
×
692
                        if ( ( in = ReadRange(in,range,1) ) == 0 ) {
×
693
                                if ( error == 0 ) error = 1;
×
694
                                return(error);
×
695
                        }
696
                        *wp++ = ARGRANGE;
×
697
                        *wp++ = range[0];
×
698
                        *wp++ = range[1];
×
699
                        *wp++ = type;
×
700
                        *work = wp-work;
×
701
                        work = wp; *wp++ = 0;
×
702
                        s = in;
×
703
                }
704
/*
705
                 #] HtoZ : 
706
*/
707
                else {
708
                        MesPrint("&Unknown transformation inside a Transform statement: %s",s);
×
709
                        *ss = c;
×
710
                        if ( error == 0 ) error = 1;
×
711
                        return(error);
×
712
                }
713
                while ( *s == ',') s++;
150✔
714
        }
715
        AT.WorkPointer[0] = TYPETRANSFORM;
138✔
716
        AT.WorkPointer[1] = i = wp - AT.WorkPointer;
138✔
717
        AddNtoL(i,AT.WorkPointer);
138✔
718
        return(error);
138✔
719
}
720

721
/*
722
                 #] CoTransform : 
723
                 #[ RunTransform :
724

725
                Executes the transform statement.
726
                This routine hunts down the functions and sends them to the various
727
                action routines.
728
                params: size,#set1,...,#setn, transformations
729

730
*/
731

732
WORD RunTransform(PHEAD WORD *term, WORD *params)
3,327✔
733
{
734
        WORD *t, *tstop, *w, *m, *out, *in, *tt, retval;
3,327✔
735
        WORD *fun, *args, *info, *infoend, *onetransform, *funs, *endfun;
3,327✔
736
        WORD *thearg = 0, *iterm, *newterm, *nt, *oldwork = AT.WorkPointer, sign = 1;
3,327✔
737
        int i;
3,327✔
738
        out = tstop = term + *term;
3,327✔
739
        tstop -= ABS(tstop[-1]);
3,327✔
740
        in = term;
3,327✔
741
        t = term + 1;
3,327✔
742
        while ( t < tstop ) {
6,717✔
743
                endfun = onetransform = params + *params;
3,390✔
744
                funs = params + 1;
3,390✔
745
                if ( *t < FUNCTION ) {}
3,390✔
746
                else if ( funs == endfun ) {  /* we do all functions */
387✔
747
hit:;
×
748
                        while ( in < t ) *out++ = *in++;
396✔
749
                        tt = t + t[1]; fun = out;
198✔
750
                        while ( in < tt ) *out++ = *in++;
17,319✔
751
                        do {
204✔
752
                                args = onetransform + 1;
204✔
753
                                info = args; while ( *info <= MAXRANGEINDICATOR ) {
408✔
754
                                        if ( *info == ALLARGS ) info++;
204✔
755
                                        else if ( *info == NUMARG ) info += 2;
204✔
756
                                        else if ( *info == ARGRANGE ) info += 3;
204✔
757
                                        else if ( *info == MAKEARGS ) info += 3;
×
758
                                }
759
                                switch ( *info ) {
204✔
760
                                        case REPLACEARG:
9✔
761
                                                if ( RunReplace(BHEAD fun,args,info) ) goto abo;
9✔
762
                                                out = fun + fun[1];
9✔
763
                                                break;
9✔
764
                                        case ENCODEARG:
3✔
765
                                                if ( RunEncode(BHEAD fun,args,info) ) goto abo;
3✔
766
                                                out = fun + fun[1];
3✔
767
                                                break;
3✔
768
                                        case DECODEARG:
×
769
                                                if ( RunDecode(BHEAD fun,args,info) ) goto abo;
×
770
                                                out = fun + fun[1];
×
771
                                                break;
×
772
                                        case IMPLODEARG:
×
773
                                                if ( RunImplode(fun,args) ) goto abo;
×
774
                                                out = fun + fun[1];
×
775
                                                break;
×
776
                                        case EXPLODEARG:
3✔
777
                                                if ( RunExplode(BHEAD fun,args) ) goto abo;
3✔
778
                                                out = fun + fun[1];
3✔
779
                                                break;
3✔
780
                                        case PERMUTEARG:
×
781
                                                if ( RunPermute(BHEAD fun,args,info) ) goto abo;
×
782
                                                out = fun + fun[1];
×
783
                                                break;
×
784
                                        case REVERSEARG:
×
785
                                                if ( RunReverse(BHEAD fun,args) ) goto abo;
×
786
                                                out = fun + fun[1];
×
787
                                                break;
×
788
                                        case DEDUPARG:
81✔
789
                                                if ( RunDedup(BHEAD fun,args) ) goto abo;
81✔
790
                                                out = fun + fun[1];
81✔
791
                                                break;
81✔
792
                                        case CYCLEARG:
×
793
                                                if ( RunCycle(BHEAD fun,args,info) ) goto abo;
×
794
                                                out = fun + fun[1];
×
795
                                                break;
×
796
                                        case ADDARG:
27✔
797
                                                if ( RunAddArg(BHEAD fun,args) ) goto abo;
27✔
798
                                                out = fun + fun[1];
27✔
799
                                                break;
27✔
800
                                        case MULTIPLYARG:
33✔
801
                                                if ( RunMulArg(BHEAD fun,args) ) goto abo;
33✔
802
                                                out = fun + fun[1];
33✔
803
                                                break;
33✔
804
                                        case ISLYNDON:
×
805
                                                if ( ( retval = RunIsLyndon(BHEAD fun,args,1) ) < -1 ) goto abo;
×
806
                                                goto returnvalues;
×
807
                                                break;
×
808
                                        case ISLYNDONR:
×
809
                                                if ( ( retval = RunIsLyndon(BHEAD fun,args,-1) ) < -1 ) goto abo;
×
810
                                                goto returnvalues;
×
811
                                                break;
×
812
                                        case TOLYNDON:
×
813
                                                if ( ( retval = RunToLyndon(BHEAD fun,args,1) ) < -1 ) goto abo;
×
814
                                                goto returnvalues;
×
815
                                                break;
×
816
                                        case TOLYNDONR:
×
817
                                                if ( ( retval = RunToLyndon(BHEAD fun,args,-1) ) < -1 ) goto abo;
×
818
returnvalues:;
×
819
                                                out = fun + fun[1];
×
820
                                                if ( retval == -1 ) break;
×
821
/*
822
                                                Work out the yes/no stuff
823
*/
824
                                                AT.WorkPointer += 2*AM.MaxTer;
×
825
                                                if ( AT.WorkPointer > AT.WorkTop ) {
×
826
                                                        MLOCK(ErrorMessageLock);
×
827
                                                        MesWork();
×
828
                                                        MUNLOCK(ErrorMessageLock);
×
829
                                                        return(-1);
×
830
                                                }
831
                                                iterm = AT.WorkPointer;
832
                                                info++;
×
833
                                                for ( i = 0; i < *info; i++ ) iterm[i] = info[i];
×
834
                                                AT.WorkPointer = iterm + *iterm;
×
835
                                                AR.Eside = LHSIDEX;
×
836
                                                NewSort(BHEAD0);
×
837
                                                if ( Generator(BHEAD iterm,AR.Cnumlhs) ) {
×
838
                                                        LowerSortLevel();
×
839
                                                        AT.WorkPointer = oldwork;
×
840
                                                        return(-1);
×
841
                                                }
842
                                                newterm = AT.WorkPointer;
×
843
                                                if ( EndSort(BHEAD newterm,1) < 0 ) {}
×
844
                                                if ( ( *newterm && *(newterm+*newterm) != 0 ) || *newterm == 0 ) {
×
845
                                                        MLOCK(ErrorMessageLock);
×
846
                                                        MesPrint("&yes/no information in islyndon/tolyndon does not evaluate into a single term");
×
847
                                                        MUNLOCK(ErrorMessageLock);
×
848
                                                        return(-1);
×
849
                                                }
850
                                                AR.Eside = RHSIDE;
×
851
                                                i = *newterm; tt = iterm; nt = newterm;
×
852
                                                NCOPY(tt,nt,i);
×
853
                                                AT.WorkPointer = iterm + *iterm;
×
854
                                                info = iterm + 1;
×
855
                                                infoend = info+info[1];
×
856
                                                info += FUNHEAD;
×
857

858
                                                if ( retval == 0 ) {
×
859
/*
860
                                                        Need second argument (=no)
861
*/
862
                                                        if ( info >= infoend ) {
×
863
abortlyndon:;
×
864
                                                                MLOCK(ErrorMessageLock);
×
865
                                                                MesPrint("There should be a yes and a no argument in islyndon/tolyndon");
×
866
                                                                MUNLOCK(ErrorMessageLock);
×
867
                                                                Terminate(-1);
×
868
                                                        }
869
                                                        NEXTARG(info)
×
870
                                                        if ( info >= infoend ) goto abortlyndon;
×
871
                                                        thearg = info;
872
                                                }
873
                                                else if ( retval == 1 ) {
×
874
/*
875
                                                        Need first argument (=yes)
876
*/
877
                                                        if ( info >= infoend ) goto abortlyndon;
×
878
                                                        thearg = info;
×
879
                                                        NEXTARG(info)
×
880
                                                        if ( info >= infoend ) goto abortlyndon;
×
881
                                                }
882
                                                NEXTARG(info)
×
883
                                                if ( info < infoend ) goto abortlyndon;
×
884
/*
885
                                                The argument in thearg needs to be copied
886
                                                We did not pull it through generator to guarantee
887
                                                that it is a single argument.
888
                                                The easiest way is to let the routine Normalize
889
                                                do the job and put everything in an exponent function
890
                                                with the power one.
891
*/
892
                                                if ( *thearg == -SNUMBER && thearg[1] == 0 ) {
×
893
                                                        *term = 0; return(0);
×
894
                                                }
895
                                                if ( *thearg == -SNUMBER && thearg[1] == 1 ) { }
×
896
                                                else {
897
                                                        fun = out;
×
898
                                                        *out++ = EXPONENT; out++; *out++ = 1; FILLFUN3(out);
×
899
                                                        COPY1ARG(out,thearg);
×
900
                                                        *out++ = -SNUMBER; *out++ = 1;
×
901
                                                        fun[1] = out-fun;
×
902
                                                }
903
                                                break;
904
                                        case DROPARG:
24✔
905
                                                if ( RunDropArg(BHEAD fun,args) ) goto abo;
24✔
906
                                                out = fun + fun[1];
24✔
907
                                                break;
24✔
908
                                        case SELECTARG:
24✔
909
                                                if ( RunSelectArg(BHEAD fun,args) ) goto abo;
24✔
910
                                                out = fun + fun[1];
24✔
911
                                                break;
24✔
912
                                        case ZTOHARG:
×
913
                                                {
914
                                                  WORD s = RunZtoHArg(BHEAD fun,args);
×
915
                                                  if ( s < 0 ) goto abo;
×
916
                                                  if ( s == 1 ) sign = -sign;
×
917
                                                  out = fun + fun[1];
×
918
                                                }
919
                                                break;
×
920
                                        case HTOZARG:
×
921
                                                {
922
                                                  WORD s = RunHtoZArg(BHEAD fun,args);
×
923
                                                  if ( s < 0 ) goto abo;
×
924
                                                  if ( s == 1 ) sign = -sign;
×
925
                                                  out = fun + fun[1];
×
926
                                                }
927
                                                break;
×
928
                                        default:
×
929
                                                MLOCK(ErrorMessageLock);
×
930
                                                MesPrint("Irregular code in execution of transform statement");
×
931
                                                MUNLOCK(ErrorMessageLock);
×
932
                                                Terminate(-1);
×
933
                                }
934
                                onetransform += *onetransform;
204✔
935
                        } while ( *onetransform );
204✔
936
                }
937
                else {
938
                  while ( funs < endfun ) {  /* sum over sets */
576✔
939
                        if ( *funs > MAXVARIABLES ) {
387✔
940
                                if ( *t == *funs-MAXVARIABLES ) goto hit;
387✔
941
                        }
942
                        else {
943
                          w = SetElements + Sets[*funs].first;
×
944
                          m = SetElements + Sets[*funs].last;
×
945
                          while ( w < m ) {  /* sum over set elements */
×
946
                                if ( *w == *t ) goto hit;
×
947
                                w++;
×
948
                          }
949
                        }
950
                        funs++;
189✔
951
                  }
952
                }
953
                t += t[1];
3,390✔
954
        }
955
        tt = term + *term; while ( in < tt ) *out++ = *in++;
55,914✔
956
        if ( sign == -1 ) out[-1] = -out[-1];
3,327✔
957
        *tt = i = out - tt;
3,327✔
958
/*
959
        Now copy the whole thing back
960
*/
961
        NCOPY(term,tt,i)
196,977✔
962
        return(0);
963
abo:
×
964
        MLOCK(ErrorMessageLock);
×
965
        MesCall("RunTransform");
×
966
        MUNLOCK(ErrorMessageLock);
×
967
        return(-1);
×
968
}
969

970
/*
971
                 #] RunTransform : 
972
                 #[ RunEncode :
973

974
                The info is given by
975
                        ENCODEARG,size,BASECODE,num
976
                and possibly more codes to follow.
977
                Only one range is allowed and for now, it should be fully numerical
978
                If the range is in reverse order, we need to either revert it
979
                first or work with an array of pointers.
980
*/
981

982
WORD RunEncode(PHEAD WORD *fun, WORD *args, WORD *info)
3✔
983
{
984
        WORD base, *f, *funstop, *fun1, *t, size1, size2, size3, *arg;
3✔
985
        int num, num1, num2, n, i, i1, i2;
3✔
986
        UWORD *scrat1, *scrat2, *scrat3;
3✔
987
        WORD *tt, *tstop, totarg, arg1, arg2;
3✔
988
        if ( functions[fun[0]-FUNCTION].spec != 0 ) return(0);
3✔
989
        if ( *args != ARGRANGE ) {
3✔
990
                MLOCK(ErrorMessageLock);
×
991
                MesPrint("Illegal range encountered in RunEncode");
×
992
                MUNLOCK(ErrorMessageLock);
×
993
                Terminate(-1);
×
994
        }
995
        tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
3✔
996
        while ( tt < tstop ) { totarg++; NEXTARG(tt); }
63✔
997
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
3✔
998
        if ( arg1 > totarg || arg2 > totarg ) return(0);
3✔
999

1000
        if ( info[2] == BASECODE ) {
3✔
1001
                base = info[3];
3✔
1002
                if ( base <= 0 ) { /* is a dollar variable */
3✔
1003
                        i1 = -base;
×
1004
                        base = DolToNumber(BHEAD i1);
×
1005
                        if ( AN.ErrorInDollar || base < 2 ) {
×
1006
                                MLOCK(ErrorMessageLock);
×
1007
                                MesPrint("$%s does not have a number value > 1 in base/encode/transform statement in module %l",
×
1008
                                        DOLLARNAME(Dollars,i1),AC.CModule);
×
1009
                                MUNLOCK(ErrorMessageLock);
×
1010
                                Terminate(-1);
×
1011
                        }
1012
                }
1013
/*
1014
                Compute number of pointers needed and make sure there is space
1015
*/
1016
                if ( arg1 > arg2 ) { num1 = arg2; num2 = arg1; }
3✔
1017
                else { num1 = arg1; num2 = arg2; }
3✔
1018
                num = num2-num1+1;
3✔
1019
                WantAddPointers(num);
6✔
1020
/*
1021
                Collect the pointers in pWorkSpace
1022
*/
1023
                n = 1; funstop = fun+fun[1]; f = fun+FUNHEAD;
3✔
1024
                while ( n < num1 ) {
3✔
1025
                        if ( f >= funstop ) return(0);
×
1026
                        NEXTARG(f);
×
1027
                        n++;
×
1028
                }
1029
                fun1 = f; i = 0;
63✔
1030
                while ( n <= num2 ) {
63✔
1031
                        if ( f >= funstop ) return(0);
60✔
1032
                        if ( *f != -SNUMBER ) {
60✔
1033
                                if ( *f < 0 ) return(0);
×
1034
                                t = f + *f - 1;
×
1035
                                i1 = ABS(*t);
×
1036
                                if ( (*f-i1) != (ARGHEAD+1) ) return(0); /* Not numerical */
×
1037
                                i1 = (i1-1)/2 - 1;
×
1038
                                t--;
×
1039
                                while ( i1 > 0 ) {
×
1040
                                        if ( *t != 0 ) return(0); /* Not an integer */
×
1041
                                        t--; i1--;
×
1042
                                }
1043
                        }
1044
                        AT.pWorkSpace[AT.pWorkPointer+i] = f;
60✔
1045
                        i++;
60✔
1046
                        NEXTARG(f);
60✔
1047
                        n++;
60✔
1048
                }
1049
/*
1050
                f points now to after the arguments; fun1 at the first.
1051
                Now check whether we need to revert the order
1052
*/
1053
                if ( arg1 > arg2 ) {
3✔
1054
                        i1 = 0; i2 = i-1;
×
1055
                        while ( i1 < i2 ) {
×
1056
                                t = AT.pWorkSpace[AT.pWorkPointer+i1];
×
1057
                                AT.pWorkSpace[AT.pWorkPointer+i1] = AT.pWorkSpace[AT.pWorkPointer+i2];
×
1058
                                AT.pWorkSpace[AT.pWorkPointer+i2] = t;
×
1059
                                i1++; i2--;
×
1060
                        }
1061
                }
1062
/*
1063
                Now we can put the thing together.
1064
                x = arg1;
1065
                x = base*x+arg2
1066
                x = base*x+arg3  etc.
1067
                We need three scratch arrays for long integers
1068
                                (see NumberMalloc in tools.c).
1069
*/
1070
                scrat1 = NumberMalloc("RunEncode");
3✔
1071
                scrat2 = NumberMalloc("RunEncode");
3✔
1072
                scrat3 = NumberMalloc("RunEncode");
3✔
1073
                arg = AT.pWorkSpace[AT.pWorkPointer];
3✔
1074
                size1 = PutArgInScratch(arg,scrat1);
3✔
1075
                i--;
3✔
1076
                while ( i > 0 ) {
60✔
1077
                        if ( MulLong(scrat1,size1,(UWORD *)(&base),1,scrat2,&size2) ) {
57✔
1078
                                NumberFree(scrat3,"RunEncode");
×
1079
                                NumberFree(scrat2,"RunEncode");
×
1080
                                NumberFree(scrat1,"RunEncode");
×
1081
                                goto CalledFrom;
×
1082
                        }
1083
                        NEXTARG(arg);
57✔
1084
                        size3 = PutArgInScratch(arg,scrat3);
57✔
1085
                        if ( AddLong(scrat2,size2,scrat3,size3,scrat1,&size1) ) {
57✔
1086
                                NumberFree(scrat3,"RunEncode");
×
1087
                                NumberFree(scrat2,"RunEncode");
×
1088
                                NumberFree(scrat1,"RunEncode");
×
1089
                                goto CalledFrom;
×
1090
                        }
1091
                        i--;
57✔
1092
                }
1093
/*
1094
                Now put the output in place. There are two cases, one being much
1095
                faster than the other. Hence we program both.
1096
                Fast: it fits inside the old location.
1097
                Slow: it does not.
1098
                The total space is f-fun1
1099
*/
1100
                if ( size1 == 0 ) {        /* Fits! */
3✔
1101
                        *fun1++ = -SNUMBER; *fun1++ = 0;
×
1102
                        while ( f < funstop ) *fun1++ = *f++;
×
1103
                        fun[1] = funstop-fun;
×
1104
                }
1105
                else if ( size1 == 1 && scrat1[0] <= MAXPOSITIVE ) { /* Fits! */
3✔
1106
                        *fun1++ = -SNUMBER; *fun1++ = scrat1[0];
3✔
1107
                        while ( f < funstop ) *fun1++ = *f++;
3✔
1108
                        fun[1] = fun1-fun;
3✔
1109
                }
1110
                else if ( size1 == -1 && scrat1[0] <= MAXPOSITIVE+1 ) { /* Fits! */
×
1111
                        *fun1++ = -SNUMBER;
×
1112
                        if ( scrat1[0] < MAXPOSITIVE ) *fun1++ = scrat1[0];
×
1113
                        else *fun1++ = (WORD)(MAXPOSITIVE+1);
×
1114
                        while ( f < funstop ) *fun1++ = *f++;
×
1115
                        fun[1] = fun1-fun;
×
1116
                }
1117
                else if ( ABS(size1)*2+2+ARGHEAD <= f-fun1 ) { /* Fits! */
×
1118
                        if ( size1 < 0 ) { size2 = size1*2-1; size1 = -size1; size3 = -size2; }
×
1119
                        else { size2 = 2*size1+1; size3 = size2; }
×
1120
                        *fun1++ = size3+ARGHEAD+1;
×
1121
                        *fun1++ = 0; FILLARG(fun1);
×
1122
                        *fun1++ = size3+1;
×
1123
                        for ( i = 0; i < size1; i++ ) *fun1++ = scrat1[i];
×
1124
                        *fun1++ = 1;
×
1125
                        for ( i = 1; i < size1; i++ ) *fun1++ = 0;
×
1126
                        *fun1++ = size2;
×
1127
                        while ( f < funstop ) *fun1++ = *f++;
×
1128
                        fun[1] = fun1-fun;
×
1129
                }
1130
                else {        /* Does not fit */
1131
                        t = funstop;
×
1132
                        if ( size1 < 0 ) { size2 = size1*2-1; size1 = -size1; size3 = -size2; }
×
1133
                        else { size2 = 2*size1+1; size3 = size2; }
×
1134
                        *t++ = size3+ARGHEAD+1;
×
1135
                        *t++ = 0; FILLARG(t);
×
1136
                        *t++ = size3+1;
×
1137
                        for ( i = 0; i < size1; i++ ) *t++ = scrat1[i];
×
1138
                        *t++ = 1;
×
1139
                        for ( i = 1; i < size1; i++ ) *t++ = 0;
×
1140
                        *t++ = size2;
×
1141
                        while ( f < funstop ) *t++ = *f++;
×
1142
                        f = funstop;
1143
                        while ( f < t ) *fun1++ = *f++;
×
1144
                        fun[1] = fun1-fun;
×
1145
                }
1146
                NumberFree(scrat3,"RunEncode");
3✔
1147
                NumberFree(scrat2,"RunEncode");
3✔
1148
                NumberFree(scrat1,"RunEncode");
3✔
1149
        }
1150
        else {
1151
                MLOCK(ErrorMessageLock);
×
1152
                MesPrint("Unimplemented type of encoding encountered in RunEncode");
×
1153
                MUNLOCK(ErrorMessageLock);
×
1154
                Terminate(-1);
×
1155
        }
1156
        return(0);
1157
CalledFrom:
×
1158
        MLOCK(ErrorMessageLock);
×
1159
        MesCall("RunEncode");
×
1160
        MUNLOCK(ErrorMessageLock);
×
1161
        return(-1);
×
1162
}
1163

1164
/*
1165
                 #] RunEncode : 
1166
                 #[ RunDecode :
1167
*/
1168

1169
WORD RunDecode(PHEAD WORD *fun, WORD *args, WORD *info)
×
1170
{
1171
        WORD base, num, num1, num2, n, *f, *funstop, *fun1, size1, size2, size3, *t;
×
1172
        WORD i1, i2, i, sig;
×
1173
        UWORD *scrat1, *scrat2, *scrat3;
×
1174
        WORD *tt, *tstop, totarg, arg1, arg2;
×
1175
        if ( functions[fun[0]-FUNCTION].spec != 0 ) return(0);
×
1176
        if ( *args != ARGRANGE ) {
×
1177
                MLOCK(ErrorMessageLock);
×
1178
                MesPrint("Illegal range encountered in RunDecode");
×
1179
                MUNLOCK(ErrorMessageLock);
×
1180
                Terminate(-1);
×
1181
        }
1182
        tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
×
1183
        while ( tt < tstop ) { totarg++; NEXTARG(tt); }
×
1184
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
×
1185
        if ( arg1 > totarg && arg2 > totarg ) return(0);
×
1186
        if ( info[2] == BASECODE ) {
×
1187
                base = info[3];
×
1188
                if ( base <= 0 ) { /* is a dollar variable */
×
1189
                        i1 = -base;
×
1190
                        base = DolToNumber(BHEAD i1);
×
1191
                        if ( AN.ErrorInDollar || base < 2 ) {
×
1192
                                MLOCK(ErrorMessageLock);
×
1193
                                MesPrint("$%s does not have a number value > 1 in base/decode/transform statement in module %l",
×
1194
                                        DOLLARNAME(Dollars,i1),AC.CModule);
×
1195
                                MUNLOCK(ErrorMessageLock);
×
1196
                                Terminate(-1);
×
1197
                        }
1198
                }
1199
/*
1200
                Compute number of output arguments needed
1201
*/
1202
                if ( arg1 > arg2 ) { num1 = arg2; num2 = arg1; }
×
1203
                else { num1 = arg1; num2 = arg2; }
×
1204
                num = num2-num1+1;
×
1205
                if ( num <= 1 ) return(0);
×
1206
/*
1207
                Find argument num1
1208
*/
1209
                funstop = fun + fun[1];
×
1210
                f = fun + FUNHEAD; n = 1;
×
1211
                while ( f < funstop ) {
×
1212
                        if ( n == num1 ) break;
×
1213
                        NEXTARG(f); n++;
×
1214
                }
1215
                if ( f >= funstop ) return(0);        /* not enough arguments */
×
1216
/*
1217
                Check that f is integer
1218
*/
1219
                if ( *f == -SNUMBER ) {}
×
1220
                else if ( *f < 0 ) return(0);
×
1221
                else {
1222
                        t = f + *f - 1;
×
1223
                        i1 = ABS(*t);
×
1224
                        if ( (*f-i1) != (ARGHEAD+1) ) return(0); /* Not numerical */
×
1225
                        i1 = (i1-1)/2 - 1;
×
1226
                        t--;
×
1227
                        while ( i1 > 0 ) {
×
1228
                                if ( *t != 0 ) return(0); /* Not an integer */
×
1229
                                t--; i1--;
×
1230
                        }
1231
                }
1232
                fun1 = f;
×
1233
/*
1234
                The argument that should be decoded is in fun1
1235
                We have to copy it to scratch
1236
*/
1237
                scrat1 = NumberMalloc("RunEncode");
×
1238
                scrat2 = NumberMalloc("RunEncode");
×
1239
                scrat3 = NumberMalloc("RunEncode");
×
1240
                size1 = PutArgInScratch(fun1,scrat1);
×
1241
                if ( size1 < 0 ) { sig = -1; size1 = -size1; }
×
1242
                else sig = 1;
1243
/*
1244
                We can check first whether this number can be decoded
1245
*/
1246
                scrat2[0] = base; size2 = 1;
×
1247
                if ( RaisPow(BHEAD scrat2,&size2,num) ) {
×
1248
                        NumberFree(scrat3,"RunEncode");
×
1249
                        NumberFree(scrat2,"RunEncode");
×
1250
                        NumberFree(scrat1,"RunEncode");
×
1251
                        goto CalledFrom;
×
1252
                }
1253
                if ( BigLong(scrat1,size1,scrat2,size2) >= 0 ) { /* Number too big */
×
1254
                        NumberFree(scrat3,"RunEncode");
×
1255
                        NumberFree(scrat2,"RunEncode");
×
1256
                        NumberFree(scrat1,"RunEncode");
×
1257
                        return(0);
×
1258
                }
1259
/*
1260
                We need num*2 spaces
1261
*/
1262
                if ( *fun1 > num*2 ) {  /* shrink space */
×
1263
                        t = fun1 + 2*num; f = fun1 + *fun1;
×
1264
                        while ( f < funstop ) *t++ = *f++;
×
1265
                        fun[1] = t - fun;
×
1266
                }
1267
                else if ( *fun1 < num*2 ) { /* case includes -SNUMBER */
×
1268
                        if ( *fun1 < 0 ) { /* expand space from -SNUMBER */
×
1269
                                fun[1] += (num-1)*2;
×
1270
                                t = funstop + (num-1)*2;
×
1271
                        }
1272
                        else { /* expand space from general argument */
1273
                                fun[1] += 2*num - *fun1;
×
1274
                                t = funstop +2*num - *fun1;
×
1275
                        }
1276
                        f = funstop;
1277
                        while ( f > fun1 ) *--t = *--f;
×
1278
                }
1279
/*
1280
                Now there is space for num -SNUMBER arguments filled from the top.
1281
*/
1282
                for ( i = num-1; i >= 0; i-- ) {
×
1283
                        DivLong(scrat1,size1,(UWORD *)(&base),1,scrat2,&size2,scrat3,&size3);
×
1284
                        fun1[2*i]   = -SNUMBER;
×
1285
                        if ( size3 == 0 ) fun1[2*i+1] = 0;
×
1286
                        else fun1[2*i+1] = (WORD)(scrat3[0])*sig;
×
1287
                        for ( i1 = 0; i1 < size2; i1++ ) scrat1[i1] = scrat2[i1];
×
1288
                        size1 = size2;
×
1289
                }
1290
                if ( size2 != 0 ) {
×
1291
                        MLOCK(ErrorMessageLock);
×
1292
                        MesPrint("RunDecode: number to be decoded is too big");
×
1293
                        MUNLOCK(ErrorMessageLock);
×
1294
                        NumberFree(scrat3,"RunEncode");
×
1295
                        NumberFree(scrat2,"RunEncode");
×
1296
                        NumberFree(scrat1,"RunEncode");
×
1297
                        goto CalledFrom;
×
1298
                }
1299
/*
1300
                Now check whether we should change the order of the arguments
1301
*/
1302
                if ( arg1 > arg2 ) {
×
1303
                        i1 = 1; i2 = 2*num-1;
×
1304
                        while ( i2 > i1 ) {
×
1305
                                i = fun1[i1]; fun1[i1] = fun1[i2]; fun1[i2] = i;
×
1306
                                i1 += 2; i2 -= 2;
×
1307
                        }
1308
                }
1309
                NumberFree(scrat3,"RunEncode");
×
1310
                NumberFree(scrat2,"RunEncode");
×
1311
                NumberFree(scrat1,"RunEncode");
×
1312
        }
1313
        else {
1314
                MLOCK(ErrorMessageLock);
×
1315
                MesPrint("Unimplemented type of encoding encountered in RunDecode");
×
1316
                MUNLOCK(ErrorMessageLock);
×
1317
                Terminate(-1);
×
1318
        }
1319
        return(0);
1320
CalledFrom:
×
1321
        MLOCK(ErrorMessageLock);
×
1322
        MesCall("RunDecode");
×
1323
        MUNLOCK(ErrorMessageLock);
×
1324
        return(-1);
×
1325
}
1326

1327
/*
1328
                 #] RunDecode : 
1329
                 #[ RunReplace :
1330

1331
                Gets the function, passes the arguments and looks whether they
1332
                need to be treated. If so, the exact treatment is found in info.
1333
                The info is given as if it is a function of type REPLACEMENT but
1334
                its name is REPLACEARG (which is NOT a function).
1335
                It is performed on the arguments.
1336
                The output is at first written after fun and in the end overwrites fun.
1337
*/
1338

1339
WORD RunReplace(PHEAD WORD *fun, WORD *args, WORD *info)
9✔
1340
{
1341
        int n = 0, i, dirty = 0, totarg, nfix, nwild, ngeneral;
9✔
1342
        WORD *t, *tt, *u, *tstop, *info1, *infoend, *oldwork = AT.WorkPointer;
9✔
1343
        WORD *term, *newterm, *nt, *term1, *term2;
9✔
1344
        WORD wild[4], mask, *term3, *term4, *oldmask = AT.WildMask;
9✔
1345
        WORD n1, n2, doanyway;
9✔
1346
        info++;
9✔
1347
        t = fun; tstop = fun + fun[1]; u = tstop;
9✔
1348
        for ( i = 0; i < FUNHEAD; i++ ) *u++ = *t++;
36✔
1349
        tt = t;
9✔
1350
        if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
9✔
1351
                totarg = 0;
1352
                while ( tt < tstop ) { totarg++; NEXTARG(tt); }
87✔
1353
        }
1354
        else {
1355
                totarg = tstop - tt;
×
1356
        }
1357
/*
1358
        Now get the info through Generator to bring it to standard form.
1359
        info points at a single term that should be sent to Generator.
1360

1361
        We want to put the information in the WorkSpace but fun etc lies there
1362
        already. This means that we have to move the WorkPointer quite high up.
1363
*/
1364
        AT.WorkPointer += 2*AM.MaxTer;
9✔
1365
        if ( AT.WorkPointer > AT.WorkTop ) {
9✔
1366
                MLOCK(ErrorMessageLock);
×
1367
                MesWork();
×
1368
                MUNLOCK(ErrorMessageLock);
×
1369
                return(-1);
×
1370
        }
1371
        term = AT.WorkPointer;
1372
        for ( i = 0; i < *info; i++ ) term[i] = info[i];
90✔
1373
        AT.WorkPointer = term + *term;
9✔
1374
        AR.Eside = LHSIDEX;
9✔
1375
        NewSort(BHEAD0);
9✔
1376
        if ( Generator(BHEAD term,AR.Cnumlhs) ) {
9✔
1377
                LowerSortLevel();
×
1378
                AT.WorkPointer = oldwork;
×
1379
                return(-1);
×
1380
        }
1381
        newterm = AT.WorkPointer;
9✔
1382
        if ( EndSort(BHEAD newterm,1) < 0 ) {}
9✔
1383
        if ( ( *newterm && *(newterm+*newterm) != 0 ) || *newterm == 0 ) {
9✔
1384
                MLOCK(ErrorMessageLock);
×
1385
                MesPrint("&information in replace transformation does not evaluate into a single term");
×
1386
                MUNLOCK(ErrorMessageLock);
×
1387
                return(-1);
×
1388
        }
1389
        AR.Eside = RHSIDE;
9✔
1390
        i = *newterm; tt = term; nt = newterm;
9✔
1391
        NCOPY(tt,nt,i);
180✔
1392
        AT.WorkPointer = term + *term;
9✔
1393
        info = term + 1;
9✔
1394

1395
        term1 = term + *term;
9✔
1396
        term2 = term1+1;
9✔
1397
        *term2++ = REPLACEMENT;
9✔
1398
        term2++; FILLFUN(term2)
9✔
1399
/*
1400
        First we count the different types of objects
1401
*/
1402
        infoend = info + info[1];
9✔
1403
        info1 = info + FUNHEAD;
9✔
1404
        nfix = nwild = ngeneral = 0;
9✔
1405
        while ( info1 < infoend ) {
24✔
1406
                if ( *info1 == -SNUMBER ) {
15✔
1407
                        nfix++; 
9✔
1408
                        info1 += 2; NEXTARG(info1)
9✔
1409
                }
1410
                else if ( *info1 <= -FUNCTION ) {
6✔
1411
                        if ( *info1 == -WILDARGFUN ) {
×
1412
                                nwild++;
×
1413
                                info1++; NEXTARG(info1)
×
1414
                        }
1415
                        else {
1416
                                *term2++ = *info1++; COPY1ARG(term2,info1)
×
1417
                                ngeneral++;
×
1418
                        }
1419
                }
1420
                else if ( *info1 == -INDEX ) {
6✔
1421
                        if ( info1[1] == WILDARGINDEX + AM.OffsetIndex ) {
×
1422
                                nwild++;
×
1423
                                info1 += 2; NEXTARG(info1)
×
1424
                        }
1425
                        else {
1426
                                *term2++ = *info1++; *term2++ = *info1++; COPY1ARG(term2,info1)
×
1427
                                ngeneral++;
×
1428
                        }
1429
                }
1430
                else if ( *info1 == -SYMBOL ) {
6✔
1431
                        if ( info1[1] == WILDARGSYMBOL ) {
6✔
1432
                                nwild++;
6✔
1433
                                info1 += 2; NEXTARG(info1)
6✔
1434
                        }
1435
                        else {
1436
                                *term2++ = *info1++; *term2++ = *info1++; COPY1ARG(term2,info1)
×
1437
                                ngeneral++;
×
1438
                        }
1439
                }
1440
                else if ( *info1 == -MINVECTOR || *info1 == -VECTOR ) {
×
1441
                        if ( info1[1] == WILDARGVECTOR + AM.OffsetVector ) {
×
1442
                                nwild++;
×
1443
                                info1 += 2; NEXTARG(info1)
×
1444
                        }
1445
                        else {
1446
                                *term2++ = *info1++; *term2++ = *info1++; COPY1ARG(term2,info1)
×
1447
                                ngeneral++;
×
1448
                        }
1449
                }
1450
                else {
1451
                        MLOCK(ErrorMessageLock);
×
1452
                        MesPrint("&irregular code found in replace transformation (RunReplace)");
×
1453
                        MUNLOCK(ErrorMessageLock);
×
1454
                        Terminate(-1);
×
1455
                }
1456
        }
1457
        AT.WorkPointer = term2;
9✔
1458
        *term1 = term2 - term1;
9✔
1459
        term1[2] = *term1 - 1;
9✔
1460
/*
1461
        And now stepping through the arguments
1462
*/
1463
        while ( t < tstop ) {
9✔
1464
                n++;        /* The number of the argument. Now check whether we need it */
78✔
1465
                if ( TestArgNum(n,totarg,args) == 0 ) {
78✔
1466
                        if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
×
1467
                                if ( *t <= -FUNCTION ) { *u++ = *t++; }
×
1468
                                else if ( *t < 0 ) { *u++ = *t++; *u++ = *t++; }
×
1469
                                else { i = *t; NCOPY(u,t,i) }
×
1470
                        }
1471
                        else *u++ = *t++;
×
1472
                        continue;
×
1473
                }
1474
/*
1475
                Here we have in info effectively a replace_ function, but with
1476
                additionally the possibility of integer arguments. We treat those first
1477
                and for the rest we have to do some pattern matching.
1478
                Note that the compilation routine should check that there is an
1479
                even number of arguments in the replace function.
1480

1481
                First we go for number -> something
1482
*/
1483
                doanyway = 0;
78✔
1484
                if ( nfix > 0 ) {
78✔
1485
                  if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
72✔
1486
                        if ( *t == -SNUMBER ) {
72✔
1487
                          info1 = info + FUNHEAD;
1488
                          while ( info1 < infoend ) {
99✔
1489
                                if ( *info1 == -SNUMBER ) {
96✔
1490
                                        if ( info1[1] == t[1] ) {
90✔
1491
                                          if ( info1[2] == -SNUMBER ) {
63✔
1492
                                                *u++ = -SNUMBER; *u++ = info1[3];
63✔
1493
                                                info1 += 4;
63✔
1494
                                          }
1495
                                          else {
1496
                                                info1 += 2;
×
1497
                                                if ( info1[0] <= -FUNCTION ) i = 1;
×
1498
                                                else if ( info1[0] < 0 ) i = 2;
×
1499
                                                else i = *info1;
×
1500
                                                NCOPY(u,info1,i)
×
1501
                                          }
1502
                                          t += 2; goto nextt;
63✔
1503
                                        }
1504
                                        info1 += 2;
27✔
1505
                                        NEXTARG(info1);
27✔
1506
                                }
1507
                                else {
1508
                                        NEXTARG(info1);
6✔
1509
                                        NEXTARG(info1);
105✔
1510
                                }
1511
                          }
1512
/*
1513
                          Here we had no match in the style of 1->2. It could however
1514
                          be that xarg_ does something
1515
*/
1516
                          doanyway = 1; n2 = t[1];
15✔
1517
                        }
1518
                  }
1519
                  else {  /* Tensor */
1520
                        if ( *t < AM.OffsetIndex && *t >= 0 ) {
×
1521
                          info1 = info + FUNHEAD;
1522
                          while ( info1 < infoend ) {
×
1523
                                if ( ( *info1 == -SNUMBER ) && ( info1[1] == *t )
×
1524
                                 && ( ( ( info1[2] == -SNUMBER ) && ( info1[3] >= 0 )
×
1525
                                 && ( info1[3] < AM.OffsetIndex ) )
×
1526
                                 || ( info1[2] == -INDEX || info1[2] == -VECTOR
×
1527
                                 || info1[2] == -MINVECTOR ) ) ) {
×
1528
                                        *u++ = info1[3];
×
1529
                                        info1 += 4;
×
1530
                                        t++; goto nextt;
×
1531
                                }
1532
                                else {
1533
                                        NEXTARG(info1);
×
1534
                                        NEXTARG(info1);
×
1535
                                }
1536
                          }
1537
                        }
1538
                  }
1539
                }
1540
                else if ( *t == -SNUMBER ) {
6✔
1541
                  doanyway = 1; n2 = t[1];
3✔
1542
                }
1543
/*
1544
                First we try to catch those elements that have an exact match
1545
                in the traditional replace_ part.
1546
                This means that *t should be less than zero and match an entry
1547
                in the replace_ function that we prepared.
1548
*/
1549
                if ( ngeneral > 0 ) {
15✔
1550
                  if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
×
1551
                        if ( *t < 0 ) {
×
1552
                                term3 = term1 + *term1;
×
1553
                                term4 = term1 + FUNHEAD;
×
1554
                                while ( term4 < term3 ) {
×
1555
                                        if ( *term4 == *t && ( *t <= -FUNCTION ||
×
1556
                                        ( t[1] == term4[1] ) ) ) break;
×
1557
                                        NEXTARG(term4)
×
1558
                                }
1559
                                if ( term4 < term3 ) goto dothisnow;
×
1560
                        }
1561
                  }
1562
                  else {
1563
                        term3 = term1 + *term1;
×
1564
                        term4 = term1 + FUNHEAD;
×
1565
                        while ( term4 < term3 ) {
×
1566
                                if ( ( term4[1] == *t ) &&
×
1567
                                        ( ( *term4 == -INDEX || *term4 == -VECTOR ||
×
1568
                                         ( *term4 == -SYMBOL && term4[1] < AM.OffsetIndex
×
1569
                                                && term4[1] >= 0 ) ) ) ) break;
×
1570
                                NEXTARG(term4)
×
1571
                        }
1572
                        if ( term4 < term3 ) goto dothisnow;
×
1573
                  }
1574
                }
1575
/*
1576
                First we eliminate the fixed arguments and make a 'new info'
1577
                If there is anything left we can continue.
1578
                Now we look for whole argument wildcards (arg_, parg_, iarg_ or farg_)
1579
*/
1580
                if ( nwild > 0 ) {
15✔
1581
/*
1582
                        If we have f(a)*replace_(xarg_,b(xarg_)) this gives f(b(a))
1583
                        In testing the wildcard we have CheckWild do the work.
1584
                        This means that we have to set op the special variables
1585
                        (AT.WildMask,AN.WildValue,AN.NumWild)
1586

1587
*/
1588
                        wild[1] = 4;
15✔
1589
                        info1 = info + FUNHEAD;
15✔
1590
                        while ( info1 < infoend ) {
15✔
1591
                                if ( *info1 == -SYMBOL && info1[1] == WILDARGSYMBOL
15✔
1592
                                && ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) ) {
15✔
1593
                                        wild[0] = SYMTOSUB;
15✔
1594
                                        wild[2] = WILDARGSYMBOL;
15✔
1595
                                        wild[3] = 0;
15✔
1596
                                        AN.WildValue = wild;
15✔
1597
                                        AT.WildMask = &mask;
15✔
1598
                                        mask = 0;
15✔
1599
                                        AN.NumWild = 1;
15✔
1600
                                        if ( *t == -SYMBOL || ( *t > 0 && CheckWild(BHEAD WILDARGSYMBOL,SYMTOSUB,1,t) == 0 )
15✔
1601
                                        || doanyway ) {
6✔
1602
/*
1603
                                                We put the part in replace in a function and make
1604
                                                a replace_(xarg_,(t argument)).
1605
*/
1606
                                                n1 = SYMBOL; n2 = WILDARGSYMBOL;
15✔
1607
                                                info1 += 2;
15✔
1608
getthisone:;
15✔
1609
                                                term3 = term2+1;
15✔
1610
                                                if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
15✔
1611
                                                        *term3++ = DUMFUN; term3++; FILLFUN(term3)
15✔
1612
                                                        COPY1ARG(term3,info1)
165✔
1613
                                                }
1614
                                                else {
1615
                                                        *term3++ = fun[0]; term3++; FILLFUN(term3)
×
1616
                                                        *term3++ = *info1;
×
1617
                                                }
1618
                                                term2[2] = term3 - term2 - 1;
15✔
1619
                                                tt = term3;
15✔
1620
                                                *term3++ = REPLACEMENT;
15✔
1621
                                                term3++; FILLFUN(term3)
15✔
1622
                                                *term3++ = -n1;
15✔
1623
                                                if ( n1 < FUNCTION ) *term3++ = n2;
15✔
1624
                                                if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
15✔
1625
                                                        term4 = t;
15✔
1626
                                                        COPY1ARG(term3,term4)
45✔
1627
                                                }
1628
                                                else {
1629
                                                        *term3++ = *t;
×
1630
                                                }
1631
                                                tt[1] = term3 - tt;
15✔
1632
                                                *term3++ = 1; *term3++ = 1; *term3++ = 3;
15✔
1633
                                                *term2 = term3 - term2;
15✔
1634

1635
                                                AT.WorkPointer = term3;
15✔
1636
                                                NewSort(BHEAD0);
15✔
1637
                                                if ( Generator(BHEAD term2,AR.Cnumlhs) ) {
15✔
1638
                                                        LowerSortLevel();
×
1639
                                                        AT.WorkPointer = oldwork;
×
1640
                                                        AT.WildMask = oldmask;
×
1641
                                                        return(-1);
×
1642
                                                }
1643
                                                term4 = AT.WorkPointer;
15✔
1644
                                                if ( EndSort(BHEAD term4,1) < 0 ) {}
15✔
1645
                                                if ( ( *term4 && *(term4+*term4) != 0 ) || *term4 == 0 ) {
15✔
1646
                                                        MLOCK(ErrorMessageLock);
×
1647
                                                        MesPrint("&information in replace transformation does not evaluate into a single term");
×
1648
                                                        MUNLOCK(ErrorMessageLock);
×
1649
                                                        return(-1);
×
1650
                                                }
1651
/*
1652
                                                Now we can copy the new function argument to the output u
1653
*/
1654
                                                i = term4[2]-FUNHEAD;
15✔
1655
                                                term3 = term4+FUNHEAD+1;
15✔
1656
                                                NCOPY(u,term3,i)
117✔
1657
                                                if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
15✔
1658
                                                        NEXTARG(t)
15✔
1659
                                                }
1660
                                                else t++;
×
1661
                                                AT.WorkPointer = term2;
15✔
1662

1663
                                                goto nextt;
15✔
1664
                                        }
1665
                                        info1 += 2; NEXTARG(info1)
×
1666
                                }
1667
                                else if ( ( *info1 == -INDEX )
×
1668
                                        && ( info[1] == WILDARGINDEX + AM.OffsetIndex ) ) {
×
1669
                                        wild[0] = INDTOSUB;
×
1670
                                        wild[2] = WILDARGINDEX+AM.OffsetIndex;
×
1671
                                        wild[3] = 0;
×
1672
                                        AN.WildValue = wild;
×
1673
                                        AT.WildMask = &mask;
×
1674
                                        mask = 0;
×
1675
                                        AN.NumWild = 1;
×
1676
                                        if ( ( functions[fun[0]-FUNCTION].spec == TENSORFUNCTION )
×
1677
                                        || ( *t == -INDEX || ( *t > 0 && CheckWild(BHEAD WILDARGINDEX,INDTOSUB,1,t) == 0 ) ) ) {
×
1678
/*
1679
                                                We put the part in replace in a function and make
1680
                                                a replace_(xarg_,(t argument)).
1681
*/
1682
                                                n1 = INDEX; n2 = WILDARGINDEX+AM.OffsetIndex;
×
1683
                                                info1 += 2;
×
1684
                                                goto getthisone;
×
1685
                                        }
1686
                                        info1 += 2; NEXTARG(info1)
×
1687
                                }
1688
                                else if ( ( *info1 == -VECTOR )
×
1689
                                        && ( info1[1] == WILDARGVECTOR + AM.OffsetVector ) ) {
×
1690
                                        wild[0] = VECTOSUB;
×
1691
                                        wild[2] = WILDARGVECTOR+AM.OffsetVector;
×
1692
                                        wild[3] = 0;
×
1693
                                        AN.WildValue = wild;
×
1694
                                        AT.WildMask = &mask;
×
1695
                                        mask = 0;
×
1696
                                        AN.NumWild = 1;
×
1697
                                        if ( functions[fun[0]-FUNCTION].spec == TENSORFUNCTION ) {
×
1698
                                                if ( *t < MINSPEC ) {
×
1699
                                                        n1 = VECTOR; n2 = WILDARGVECTOR+AM.OffsetVector;
×
1700
                                                        info1 += 2;
×
1701
                                                        goto getthisone;
×
1702
                                                }
1703
                                        }
1704
                                        else if ( *t == -VECTOR || *t == -MINVECTOR ||
×
1705
                                        ( *t > 0 && CheckWild(BHEAD WILDARGVECTOR,VECTOSUB,1,t) == 0 ) ) {
×
1706
/*
1707
                                                We put the part in replace in a function and make
1708
                                                a replace_(xarg_,(t argument)).
1709
*/
1710
                                                n1 = VECTOR; n2 = WILDARGVECTOR+AM.OffsetVector;
×
1711
                                                info1 += 2;
×
1712
                                                goto getthisone;
×
1713
                                        }
1714
                                        info1 += 2; NEXTARG(info1)
×
1715
                                }
1716
                                else if ( *info1 == -WILDARGFUN ) {
×
1717
                                        wild[0] = FUNTOFUN;
×
1718
                                        wild[2] = WILDARGFUN;
×
1719
                                        wild[3] = 0;
×
1720
                                        AN.WildValue = wild;
×
1721
                                        AT.WildMask = &mask;
×
1722
                                        mask = 0;
×
1723
                                        AN.NumWild = 1;
×
1724
                                        if ( *t <= -FUNCTION || ( *t > 0 && CheckWild(BHEAD WILDARGFUN,FUNTOFUN,1,t) == 0 ) ) {
×
1725
/*
1726
                                                We put the part in replace in a function and make
1727
                                                a replace_(xarg_,(t argument)).
1728
*/
1729
                                                n2 = n1 = -WILDARGFUN; /* n2 is to keep the compiler quiet */
×
1730
                                                info1++;
×
1731
                                                goto getthisone;
×
1732
                                        }
1733
                                        info1++; NEXTARG(info1)
×
1734
                                }
1735
                                else {
1736
                                        NEXTARG(info1) NEXTARG(info1)
×
1737
                                }
1738
                        }
1739
                }
1740
                if ( ngeneral > 0 ) {
×
1741
/*
1742
                        They are all in a replace_ function.
1743
                        Compose the whole thing into a term with replace_()*dum_(arg)
1744
                        which will be given to Generator.
1745
                        If we have f(a(x))*replace_(x,b) this gives f(a(b))
1746
*/
1747
dothisnow:;
×
1748
                        term3 = term2; term4 = term1; i = *term1;
×
1749
                        NCOPY(term3,term4,i)
×
1750
                        term4 = term3;
×
1751
                        if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
×
1752
                                *term3++ = DUMFUN; term3++; FILLFUN(term3);
×
1753
                                tt = t;
×
1754
                                COPY1ARG(term3,tt)
×
1755
                        }
1756
                        else {
1757
                                *term3++ = fun[0]; term3++; FILLFUN(term3); *term3++ = *t;
×
1758
                        }
1759
                        term4[1] = term3-term4;
×
1760
                        *term3++ = 1; *term3++ = 1; *term3++ = 3;
×
1761
                        *term2 = term3-term2;
×
1762
                        AT.WorkPointer = term3;
×
1763
                        NewSort(BHEAD0);
×
1764
                        if ( Generator(BHEAD term2,AR.Cnumlhs) ) {
×
1765
                                LowerSortLevel();
×
1766
                                AT.WorkPointer = oldwork;
×
1767
                                AT.WildMask = oldmask;
×
1768
                                return(-1);
×
1769
                        }
1770
                        term4 = AT.WorkPointer;
×
1771
                        if ( EndSort(BHEAD term4,1) < 0 ) {}
×
1772
                        if ( ( *term4 && *(term4+*term4) != 0 ) || *term4 == 0 ) {
×
1773
                                MLOCK(ErrorMessageLock);
×
1774
                                MesPrint("&information in replace transformation does not evaluate into a single term");
×
1775
                                MUNLOCK(ErrorMessageLock);
×
1776
                                return(-1);
×
1777
                        }
1778
/*
1779
                        Now we can copy the new function argument to the output u
1780
*/
1781
                        i = term4[2]-FUNHEAD;
×
1782
                        term3 = term4+FUNHEAD+1;
×
1783
                        NCOPY(u,term3,i)
×
1784
                        NEXTARG(t)
×
1785
                        AT.WorkPointer = term2;
×
1786

1787
                        goto nextt;
×
1788
                }
1789

1790
/*
1791
                No catch. Copy the argument and continue.
1792
*/                
1793
                if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
×
1794
                        if ( *t <= -FUNCTION ) { *u++ = *t++; }
×
1795
                        else if ( *t < 0 ) { *u++ = *t++; *u++ = *t++; }
×
1796
                        else { i = *t; NCOPY(u,t,i) }
×
1797
                }
1798
                else {
1799
                        *u++ = *t++;
×
1800
                }
1801
nextt:;
87✔
1802
        }
1803
        i = u - tstop; tstop[1] = i; tstop[2] = dirty;
9✔
1804
        t = fun; u = tstop; NCOPY(t,u,i)
264✔
1805
        AT.WorkPointer = oldwork;
9✔
1806
        AT.WildMask = oldmask;
9✔
1807
        return(0);
9✔
1808
}
1809

1810
/*
1811
                 #] RunReplace : 
1812
                 #[ RunImplode :
1813

1814
                Note that we restrict ourselves to short integers and/or single symbols
1815
*/
1816

1817
WORD RunImplode(WORD *fun, WORD *args)
×
1818
{
1819
        GETIDENTITY
1820
        WORD *tt, *tstop, totarg, arg1, arg2, num1, num2, i1, n;
×
1821
        WORD *f, *t, *ttt, *t4, *ff, *fff;
×
1822
        WORD moveup, numzero, outspace;
×
1823
        if ( functions[fun[0]-FUNCTION].spec != 0 ) return(0);
×
1824
        if ( *args != ARGRANGE ) {
×
1825
                MLOCK(ErrorMessageLock);
×
1826
                MesPrint("Illegal range encountered in RunImplode");
×
1827
                MUNLOCK(ErrorMessageLock);
×
1828
                Terminate(-1);
×
1829
        }
1830
        tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
×
1831
        while ( tt < tstop ) { totarg++; NEXTARG(tt); }
×
1832
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
×
1833
/*
1834
        Get the proper range in forward direction and the number of arguments
1835
*/
1836
        if ( arg1 > arg2 ) { num1 = arg2; num2 = arg1; }
×
1837
        else { num1 = arg1; num2 = arg2; }
×
1838
        if ( num1 > totarg || num2 > totarg ) return(0);
×
1839
/*
1840
        We need, for the most general case 4 spots for each:
1841
                        x,pow,coef,sign
1842
        Hence we put these in the workspace above the term after tstop
1843
*/
1844
        n = 1; f = fun+FUNHEAD;
1845
        while ( n < num1 ) {
×
1846
                if ( f >= tstop ) return(0);
×
1847
                NEXTARG(f);
×
1848
                n++;
×
1849
        }
1850
        ff = f;
×
1851
/*
1852
        We are now at the first argument to be done        
1853
        Go through the terms and test their validity.
1854
        If one of them doesn't conform to the rules we don't do anything.
1855
        The terms to be done are put in special notation after the function.
1856
        Notation: numsymbol, power, |coef|, sign
1857
        If numsymbol is negative there is no symbol.
1858
        We do it this way because otherwise stepping backwards (as in range=(4,1))
1859
        would be very difficult.
1860
*/
1861
        tt = tstop;
1862
        while ( n <= num2 ) {
×
1863
                if ( f >= tstop ) return(0);
×
1864
                if ( *f == -SNUMBER ) { *tt++ = -1; *tt++ = 0;
×
1865
                        if ( f[1] < 0 ) { *tt++ = -f[1]; *tt++ = -1; }
×
1866
                        else { *tt++ = f[1]; *tt++ = 1; }
×
1867
                        f += 2;
×
1868
                }
1869
                else if ( *f == -SYMBOL ) { *tt++ = f[1]; *tt++ = 1; *tt++ = 1; *tt++ = 1; f += 2; }
×
1870
                else if ( *f < 0 ) return(0);
×
1871
                else {
1872
                        if ( *f != ( f[ARGHEAD]+ARGHEAD ) ) return(0); /* Not a single term */
×
1873
                        t = f + *f - 1;
×
1874
                        i1 = ABS(*t);
×
1875
                        if ( ( i1 > 3 ) || ( t[-1] != 1 ) ) return(0); /* Not an integer or too big */
×
1876
                        if ( (UWORD)(t[-2]) > MAXPOSITIVE4 ) return(0); /* number too big */
×
1877
                        if ( f[ARGHEAD] == i1+1 ) { /* numerical which is fine */
×
1878
                                *tt++ = -1; *tt++ = 0; *tt++ = t[-2];
×
1879
                                if ( *t < 0 ) { *tt++ = -1; }
×
1880
                                else { *tt++ = 1; }
×
1881
                        }
1882
                        else if ( ( f[ARGHEAD+1] != SYMBOL )
×
1883
                                 || ( f[ARGHEAD+2] != 4 )
×
1884
                                 || ( ( f+ARGHEAD+1+f[ARGHEAD+2] ) < ( t-i1 ) ) ) return(0);
×
1885
                                        /* not a single symbol with a coefficient */
1886
                        else {
1887
                                *tt++ = f[ARGHEAD+3];
×
1888
                                *tt++ = f[ARGHEAD+4];
×
1889
                                *tt++ = t[-2];
×
1890
                                if ( *t < 0 ) { *tt++ = -1; }
×
1891
                                else { *tt++ = 1; }
×
1892
                        }
1893
                        f += *f;
×
1894
                }
1895
                n++;
×
1896
        }
1897
        fff = f;
×
1898
/*
1899
        At this point we can do the implosion.
1900
        Requirement: no coefficient shall take more than one word.
1901
        (a stricter requirement may be needed to keep the explosion contained)
1902
*/
1903
        if ( arg1 > arg2 ) {
×
1904
/*
1905
                Work backward.
1906
*/
1907
                t = tt - 4; numzero = 0;
×
1908
                while ( t >= tstop ) {
×
1909
                        if ( t[2] == 0 ) numzero++;
×
1910
                        else {
1911
                                if ( numzero > 0 ) {
×
1912
                                        t[2] += numzero;
×
1913
                                        t4 = t+4;
×
1914
                                        ttt = t4 + 4*numzero;
×
1915
                                        while ( ttt < tt ) *t4++ = *ttt++;
×
1916
                                        tt -= 4*numzero;
×
1917
                                        numzero = 0;
×
1918
                                }
1919
                        }
1920
                        t -= 4;
×
1921
                }
1922
        }
1923
        else {
1924
                t = tstop;
1925
                numzero = 0; ttt = t;
1926
                while ( t < tt ) {
×
1927
                        if ( t[2] == 0 ) numzero++;
×
1928
                        else {
1929
                                if ( numzero > 0 ) {
×
1930
                                        t[2] += numzero;
×
1931
                                        t4 = t;
×
1932
                                        while ( t4 < tt ) *ttt++ = *t4++;
×
1933
                                        tt -= 4*numzero;
×
1934
                                        t -= 4*numzero;
×
1935
                                        ttt = t + 4;
×
1936
                                        numzero = 0;
×
1937
                                }
1938
                                else {
1939
                                        ttt = t + 4;
×
1940
                                }
1941
                        }
1942
                        t += 4;
×
1943
                }
1944
/*
1945
                We may have numzero > 0 at the end. We leave them.
1946
                Output space is currently from tstop to tt
1947
*/
1948
        }
1949
/*
1950
        Now we compute the real output space needed
1951
*/
1952
        t = tstop; outspace = 0;
×
1953
        while ( t < tt ) {
×
1954
                if ( t[0] == -1 ) {
×
1955
                        if ( t[2] > MAXPOSITIVE4 ) { return(0); /* Number too big */ }
×
1956
                        outspace += 2;
×
1957
                }
1958
                else if ( t[1] == 1 && t[2] == 1 && t[3] == 1 ) { outspace += 2; }
×
1959
                else { outspace += 8 + ARGHEAD; }
×
1960
                t += 4;
×
1961
        }
1962
        if ( outspace < (fff-ff) ) {
×
1963
                t = tstop;
1964
                while ( t < tt ) {
×
1965
                        if ( t[0] == -1 ) { *ff++ = -SNUMBER; *ff++ = t[2]*t[3]; }
×
1966
                        else if ( t[1] == 1 && t[2] == 1 && t[3] == 1 ) {
×
1967
                                *ff++ = -SYMBOL; *ff++ = t[0];
×
1968
                        }
1969
                        else {
1970
                                *ff++ = 8+ARGHEAD; *ff++ = 0; FILLARG(ff);
×
1971
                                *ff++ = 8; *ff++ = SYMBOL; *ff++ = 4; *ff++ = t[0]; *ff++ = t[1];
×
1972
                                *ff++ = t[2]; *ff++ = 1; *ff++ = t[3] > 0 ? 3: -3;
×
1973
                        }
1974
                        t += 4;
×
1975
                }
1976
                while ( fff < tstop ) *ff++ = *fff++;
×
1977
                fun[1] = ff - fun;
×
1978
        }
1979
        else if ( outspace > (fff-ff) ) {
×
1980
/*
1981
                Move the answer up by the required amount.
1982
                Move the tail to its new location
1983
                Move in things as for outspace == (fff-ff)
1984
*/
1985
                moveup = outspace-(fff-ff);
×
1986
                ttt = tt + moveup;
×
1987
                t = tt;
×
1988
                while ( t > fff ) *--ttt = *--t;
×
1989
                tt += moveup; tstop += moveup;
×
1990
                fff += moveup;
×
1991
                fun[1] += moveup;
×
1992
                goto moveinto;
×
1993
        }
1994
        else {
1995
moveinto:
×
1996
                t = tstop;
×
1997
                while ( t < tt ) {
×
1998
                        if ( t[0] == -1 ) { *ff++ = -SNUMBER; *ff++ = t[2]*t[3]; }
×
1999
                        else if ( t[1] == 1 && t[2] == 1 && t[3] == 1 ) {
×
2000
                                *ff++ = -SYMBOL; *ff++ = t[0];
×
2001
                        }
2002
                        else {
2003
                                *ff++ = 8+ARGHEAD; *ff++ = 0; FILLARG(ff);
×
2004
                                *ff++ = 8; *ff++ = SYMBOL; *ff++ = 4; *ff++ = t[0]; *ff++ = t[1];
×
2005
                                *ff++ = t[2]; *ff++ = 1; *ff++ = t[3] > 0 ? 3: -3;
×
2006
                        }
2007
                        t += 4;
×
2008
                }
2009
        }
2010
        return(0);
2011
}
2012

2013
/*
2014
                 #] RunImplode : 
2015
                 #[ RunExplode :
2016
*/
2017

2018
WORD RunExplode(PHEAD WORD *fun, WORD *args)
3✔
2019
{
2020
        WORD arg1, arg2, num1, num2, *tt, *tstop, totarg, *tonew, *newfun;
3✔
2021
        WORD *ff, *f;
3✔
2022
        int reverse = 0, iarg, i, numzero;
3✔
2023
        if ( functions[fun[0]-FUNCTION].spec != 0 ) return(0);
3✔
2024
        if ( *args != ARGRANGE ) {
3✔
2025
                MLOCK(ErrorMessageLock);
×
2026
                MesPrint("Illegal range encountered in RunExplode");
×
2027
                MUNLOCK(ErrorMessageLock);
×
2028
                Terminate(-1);
×
2029
        }
2030
        tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
3✔
2031
        while ( tt < tstop ) { totarg++; NEXTARG(tt); }
27✔
2032
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
3✔
2033
/*
2034
        Get the proper range in forward direction and the number of arguments
2035
*/
2036
        if ( arg1 > arg2 ) { num1 = arg2; num2 = arg1; reverse = 1; }
3✔
2037
        else { num1 = arg1; num2 = arg2; }
3✔
2038
        if ( num1 > totarg || num2 > totarg ) return(0);
3✔
2039
        if ( tstop + AM.MaxTer > AT.WorkTop ) goto OverWork;
3✔
2040
/*
2041
        We will make the new function after the old one in the workspace
2042
        Find the first argument
2043
*/
2044
        tonew = newfun = tstop;
3✔
2045
        ff = fun + FUNHEAD; iarg = 0;
2046
        while ( ff < tstop ) {
3✔
2047
                iarg++;
3✔
2048
                if ( iarg == num1 ) {
3✔
2049
                        i = ff - fun; f = fun;
3✔
2050
                        NCOPY(tonew,f,i)
12✔
2051
                        break;
2052
                }
2053
                NEXTARG(ff)
×
2054
        }
2055
/*
2056
        We have reached the first argument to be done
2057
*/
2058
        while ( iarg <= num2 ) {
27✔
2059
                if ( *ff == -SYMBOL || ( *ff == -SNUMBER && ff[1] == 0 ) )
24✔
2060
                        { *tonew++ = *ff++; *tonew++ = *ff++; }
×
2061
                else if ( *ff == -SNUMBER ) {
24✔
2062
                        numzero = ABS(ff[1])-1;
24✔
2063
                        if ( reverse ) {
24✔
2064
                                *tonew++ = -SNUMBER; *tonew++ = ff[1] < 0 ? -1: 1;
×
2065
                                while ( numzero > 0 ) {
×
2066
                                        *tonew++ = -SNUMBER; *tonew++ = 0; numzero--;
×
2067
                                }
2068
                        }
2069
                        else {
2070
                                while ( numzero > 0 ) {
60✔
2071
                                        *tonew++ = -SNUMBER; *tonew++ = 0; numzero--;
36✔
2072
                                }
2073
                                *tonew++ = -SNUMBER; *tonew++ = ff[1] < 0 ? -1: 1;
48✔
2074
                        }
2075
                        ff += 2;
24✔
2076
                }
2077
                else if ( *ff < 0 ) { return(0); }
×
2078
                else {
2079
                        if ( *ff != ARGHEAD+8 || ff[ARGHEAD] != 8
×
2080
                                 || ff[ARGHEAD+1] != SYMBOL || ABS(ff[ARGHEAD+7]) != 3
×
2081
                                 || ff[ARGHEAD+6] != 1 ) return(0);
×
2082
                        numzero = ff[ARGHEAD+5];
×
2083
                        if ( numzero >= MAXPOSITIVE4 ) return(0);
×
2084
                        numzero--;
×
2085
                        if ( reverse ) {
×
2086
                                if ( ff[ARGHEAD+7] > 0 ) { *tonew++ = -SNUMBER; *tonew++ = 1; }
×
2087
                                else {
2088
                                        *tonew++ = ARGHEAD+8; *tonew++ = 0; FILLARG(tonew)
×
2089
                                        *tonew++ = 8; *tonew++ = SYMBOL; *tonew++ = ff[ARGHEAD+3];
×
2090
                                        *tonew++ = ff[ARGHEAD+4]; *tonew++ = 1; *tonew++ = 1;
×
2091
                                        *tonew++ = -3;
×
2092
                                }
2093
                                while ( numzero > 0 ) {
×
2094
                                        *tonew++ = -SNUMBER; *tonew++ = 0; numzero--;
×
2095
                                }
2096
                        }
2097
                        else {
2098
                                while ( numzero > 0 ) {
×
2099
                                        *tonew++ = -SNUMBER; *tonew++ = 0; numzero--;
×
2100
                                }
2101
                                *tonew++ = ARGHEAD+8; *tonew++ = 0; FILLARG(tonew)
×
2102
                                *tonew++ = 8; *tonew++ = SYMBOL; *tonew++ = 4;
×
2103
                                *tonew++ = ff[ARGHEAD+3]; *tonew++ = ff[ARGHEAD+4];
×
2104
                                *tonew++ = 1; *tonew++ = 1;
×
2105
                                if ( ff[ARGHEAD+7] > 0 ) *tonew++ = 3;
×
2106
                                else                     *tonew++ = -3;
×
2107
                        }
2108
                        ff += *ff;
×
2109
                }
2110
                if ( tonew > AT.WorkTop ) goto OverWork;
24✔
2111
                iarg++;
24✔
2112
        }
2113
/*
2114
        Copy the tail, settle the size and copy the whole thing back.
2115
*/
2116
        while ( ff < tstop ) *tonew++ = *ff++;
3✔
2117
        i = newfun[1] = tonew-newfun;
3✔
2118
        NCOPY(fun,newfun,i)
132✔
2119
        return(0);
2120
OverWork:;
×
2121
        MLOCK(ErrorMessageLock);
×
2122
        MesWork();
×
2123
        MUNLOCK(ErrorMessageLock);
×
2124
        return(-1);
×
2125
}
2126

2127
/*
2128
                 #] RunExplode : 
2129
                 #[ RunPermute :
2130
*/
2131

2132
WORD RunPermute(PHEAD WORD *fun, WORD *args, WORD *info)
×
2133
{
2134
        WORD *tt, totarg, *tstop, arg1, arg2, n, num, i, *f, *f1, *f2, *infostop;
×
2135
        WORD *in, *iw, withdollar;
×
2136
        DOLLARS d;
×
2137
        if ( *args != ARGRANGE ) {
×
2138
                MLOCK(ErrorMessageLock);
×
2139
                MesPrint("Illegal range encountered in RunPermute");
×
2140
                MUNLOCK(ErrorMessageLock);
×
2141
                Terminate(-1);
×
2142
        }
2143
        if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
×
2144
          tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
×
2145
          while ( tt < tstop ) { totarg++; NEXTARG(tt); }
×
2146
          arg1 = 1; arg2 = totarg;
×
2147
/*
2148
          We need to:
2149
                1: get pointers to the arguments
2150
                2: permute the pointers
2151
                3: copy the arguments to safe territory in the new order
2152
                4: copy this new order back in situ.
2153
*/
2154
          num = arg2-arg1+1;
×
2155
          WantAddPointers(num);        /* Guarantees the presence of enough pointers */
×
2156
          f = fun+FUNHEAD; n = 1; i = 0;
2157
          while ( n < arg1 ) { n++; NEXTARG(f) }
2158
          f1 = f;
×
2159
          while ( n <= arg2 ) { AT.pWorkSpace[AT.pWorkPointer+i++] = f; n++; NEXTARG(f) }
×
2160
/*
2161
          Now the permutations
2162
*/
2163
          info++;
×
2164
          while ( *info ) {
×
2165
                infostop = info + *info;
×
2166
                info++;
×
2167
                if ( *info > totarg ) return(0);
×
2168
/*
2169
                Now we have a look whether there are dollar variables to be expanded
2170
                We also shift out all values that are out of range.
2171
*/
2172
                withdollar = 0;  in = info;
2173
                while ( in < infostop ) {
×
2174
                        if ( *in < 0 ) { /* Dollar variable -(number+1) */
×
2175
                                d = Dollars - *in - 1;
×
2176
#ifdef WITHPTHREADS
2177
                                {
2178
                                        int nummodopt, dtype = -1, numdollar = -*in-1;
2179
                                        if ( AS.MultiThreaded && ( AC.mparallelflag == PARALLELFLAG ) ) {
2180
                                                for ( nummodopt = 0; nummodopt < NumModOptdollars; nummodopt++ ) {
2181
                                                        if ( numdollar == ModOptdollars[nummodopt].number ) break;
2182
                                                }
2183
                                                if ( nummodopt < NumModOptdollars ) {
2184
                                                        dtype = ModOptdollars[nummodopt].type;
2185
                                                        if ( dtype == MODLOCAL ) {
2186
                                                                d = ModOptdollars[nummodopt].dstruct+AT.identity;
2187
                                                        }
2188
                                                        else {
2189
                                                                LOCK(d->pthreadslockread);
2190
                                                        }
2191
                                                }
2192
                                        }
2193
                                }
2194
#endif
2195
                                if ( ( d->type == DOLNUMBER || d->type == DOLTERMS )
×
2196
                                 && d->where[0] == 4 && d->where[4] == 0 ) {
×
2197
                                        if ( d->where[3] < 0 || d->where[2] != 1 || d->where[1] > totarg ) return(0);
×
2198
                                }
2199
                                else if ( d->type == DOLWILDARGS ) {
×
2200
                                        iw = d->where+1;
×
2201
                                        while ( *iw ) {
×
2202
                                                if ( *iw == -SNUMBER ) {
×
2203
                                                        if ( iw[1] <= 0 || iw[1] > totarg ) return(0);
×
2204
                                                }
2205
                                                else goto IllType;
×
2206
                                                iw += 2;
×
2207
                                        }
2208
                                }
2209
                                else {
2210
IllType:
×
2211
                    MLOCK(ErrorMessageLock);
×
2212
                                        MesPrint("Illegal type of $-variable in RunPermute");
×
2213
                                        MUNLOCK(ErrorMessageLock);
×
2214
                                        Terminate(-1);
×
2215
                                }
2216
                                withdollar++;
×
2217
                        }
2218
                        else if ( *in > totarg ) return(0);
×
2219
                        in++;
×
2220
                }
2221
                if ( withdollar ) { /* We need some space for a copy */
×
2222
                        WORD *incopy, *tocopy;
×
2223
                        incopy = TermMalloc("RunPermute");
×
2224
                        tocopy = incopy+1; in = info;
×
2225
                        while ( in < infostop ) {
×
2226
                                if ( *in < 0 ) {
×
2227
                                        d = Dollars - *in - 1;
×
2228
#ifdef WITHPTHREADS
2229
                                {
2230
                                        int nummodopt, dtype = -1, numdollar = -*in-1;
2231
                                        if ( AS.MultiThreaded && ( AC.mparallelflag == PARALLELFLAG ) ) {
2232
                                                for ( nummodopt = 0; nummodopt < NumModOptdollars; nummodopt++ ) {
2233
                                                        if ( numdollar == ModOptdollars[nummodopt].number ) break;
2234
                                                }
2235
                                                if ( nummodopt < NumModOptdollars ) {
2236
                                                        dtype = ModOptdollars[nummodopt].type;
2237
                                                        if ( dtype == MODLOCAL ) {
2238
                                                                d = ModOptdollars[nummodopt].dstruct+AT.identity;
2239
                                                        }
2240
                                                        else {
2241
                                                                LOCK(d->pthreadslockread);
2242
                                                        }
2243
                                                }
2244
                                        }
2245
                                }
2246
#endif
2247
                                        if ( d->type == DOLNUMBER || d->type == DOLTERMS ) {
×
2248
                                                *tocopy++ = d->where[1] - 1;
×
2249
                                        }
2250
                                        else if ( d->type == DOLWILDARGS ) {
×
2251
                                                iw = d->where+1;
×
2252
                                                while ( *iw ) {
×
2253
                                                        *tocopy++ = iw[1] - 1;
×
2254
                                                        iw += 2;
×
2255
                                                }
2256
                                        }
2257
                                        in++;
×
2258
                                }
2259
                                else *tocopy++ = *in++;
×
2260
                        }
2261
                        *tocopy = 0;
×
2262
                        *incopy = tocopy - incopy;
×
2263
                        in = incopy+1;
×
2264
                        tt = AT.pWorkSpace[AT.pWorkPointer+*in];
×
2265
                        in++;
×
2266
                        while ( in < tocopy ) {
×
2267
                                if ( *in > totarg ) return(0);
×
2268
                                AT.pWorkSpace[AT.pWorkPointer+in[-1]] = AT.pWorkSpace[AT.pWorkPointer+*in];
×
2269
                                in++;
×
2270
                        }
2271
                        AT.pWorkSpace[AT.pWorkPointer+in[-1]] = tt;
×
2272
                        TermFree(incopy,"RunPermute");
×
2273
                        info = infostop;
×
2274
                }
2275
                else {
2276
                        tt = AT.pWorkSpace[AT.pWorkPointer+*info];
×
2277
                        info++;
×
2278
                        while ( info < infostop ) {
×
2279
                                if ( *info > totarg ) return(0);
×
2280
                                AT.pWorkSpace[AT.pWorkPointer+info[-1]] = AT.pWorkSpace[AT.pWorkPointer+*info];
×
2281
                                info++;
×
2282
                        }
2283
                        AT.pWorkSpace[AT.pWorkPointer+info[-1]] = tt;
×
2284
                }
2285
          }
2286
/*
2287
          info++;
2288
          while ( *info ) {
2289
                infostop = info + *info;
2290
                info++;
2291
                if ( *info > totarg ) return(0);
2292
                tt = AT.pWorkSpace[AT.pWorkPointer+*info];
2293
                info++;
2294
                while ( info < infostop ) {
2295
                        if ( *info > totarg ) return(0);
2296
                        AT.pWorkSpace[AT.pWorkPointer+info[-1]] = AT.pWorkSpace[AT.pWorkPointer+*info];
2297
                        info++;
2298
                }
2299
                AT.pWorkSpace[AT.pWorkPointer+info[-1]] = tt;
2300
          }
2301
*/
2302
/*
2303
          And the final cleanup
2304
*/
2305
          if ( tstop+(f-f1) > AT.WorkTop ) goto OverWork;
×
2306
          f2 = tstop;
2307
          for ( i = 0; i < num; i++ ) { f = AT.pWorkSpace[AT.pWorkPointer+i]; COPY1ARG(f2,f) }
×
2308
          i = f2 - tstop;
×
2309
          NCOPY(f1,tstop,i)
×
2310
        }
2311
        else {  /* tensors */
2312
          tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = tstop-tt;
×
2313
          arg1 = 1; arg2 = totarg;
×
2314
          num = arg2-arg1+1;
×
2315
          WantAddPointers(num);        /* Guarantees the presence of enough pointers */
×
2316
          f = fun+FUNHEAD; n = 1; i = 0;
×
2317
          while ( n < arg1 ) { n++; f++; }
×
2318
          f1 = f;
×
2319
          while ( n <= arg2 ) { AT.pWorkSpace[AT.pWorkPointer+i++] = f; n++; f++; }
×
2320
/*
2321
          Now the permutations
2322
*/
2323
          info++;
×
2324
          while ( *info ) {
×
2325
                infostop = info + *info;
×
2326
                info++;
×
2327
                if ( *info > totarg ) return(0);
×
2328
                tt = AT.pWorkSpace[AT.pWorkPointer+*info];
×
2329
                info++;
×
2330
                while ( info < infostop ) {
×
2331
                        if ( *info > totarg ) return(0);
×
2332
                        AT.pWorkSpace[AT.pWorkPointer+info[-1]] = AT.pWorkSpace[AT.pWorkPointer+*info];
×
2333
                        info++;
×
2334
                }
2335
                AT.pWorkSpace[AT.pWorkPointer+info[-1]] = tt;
×
2336
          }
2337
/*
2338
          And the final cleanup
2339
*/
2340
          if ( tstop+(f-f1) > AT.WorkTop ) goto OverWork;
×
2341
          f2 = tstop;
2342
          for ( i = 0; i < num; i++ ) { f = AT.pWorkSpace[AT.pWorkPointer+i]; *f2++= *f++; }
×
2343
          i = f2 - tstop;
×
2344
          NCOPY(f1,tstop,i)
×
2345
        }
2346
        return(0);
2347
OverWork:;
×
2348
        MLOCK(ErrorMessageLock);
×
2349
        MesWork();
×
2350
        MUNLOCK(ErrorMessageLock);
×
2351
        return(-1);
×
2352
}
2353

2354
/*
2355
                 #] RunPermute : 
2356
                 #[ RunReverse :
2357
*/
2358

2359
WORD RunReverse(PHEAD WORD *fun, WORD *args)
×
2360
{
2361
        WORD *tt, totarg, *tstop, arg1, arg2, n, num, i, *f, *f1, *f2, i1, i2;
×
2362
        if ( *args != ARGRANGE ) {
×
2363
                MLOCK(ErrorMessageLock);
×
2364
                MesPrint("Illegal range encountered in RunReverse");
×
2365
                MUNLOCK(ErrorMessageLock);
×
2366
                Terminate(-1);
×
2367
        }
2368
        if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
×
2369
          tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
×
2370
          while ( tt < tstop ) { totarg++; NEXTARG(tt); }
×
2371
          if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
×
2372
/*
2373
          We need to:
2374
                1: get pointers to the arguments
2375
                2: reverse the order of the pointers
2376
                3: copy the arguments to safe territory in the new order
2377
                4: copy this new order back in situ.
2378
*/
2379
          if ( arg2 < arg1 ) { n = arg1; arg1 = arg2; arg2 = n; }
×
2380
          if ( arg2 > totarg ) return(0);
×
2381

2382
          num = arg2-arg1+1;
×
2383
          WantAddPointers(num);        /* Guarantees the presence of enough pointers */
×
2384
          f = fun+FUNHEAD; n = 1; i = 0;
×
2385
          while ( n < arg1 ) { n++; NEXTARG(f) }
×
2386
          f1 = f;
×
2387
          while ( n <= arg2 ) { AT.pWorkSpace[AT.pWorkPointer+i++] = f; n++; NEXTARG(f) }
×
2388
          i1 = i-1; i2 = 0;
×
2389
          while ( i1 > i2 ) {
×
2390
                tt = AT.pWorkSpace[AT.pWorkPointer+i1];
×
2391
                AT.pWorkSpace[AT.pWorkPointer+i1] = AT.pWorkSpace[AT.pWorkPointer+i2];
×
2392
                AT.pWorkSpace[AT.pWorkPointer+i2] = tt;
×
2393
                i1--; i2++;
×
2394
          }
2395
          if ( tstop+(f-f1) > AT.WorkTop ) goto OverWork;
×
2396
          f2 = tstop;
2397
          for ( i = 0; i < num; i++ ) { f = AT.pWorkSpace[AT.pWorkPointer+i]; COPY1ARG(f2,f) }
×
2398
          i = f2 - tstop;
×
2399
          NCOPY(f1,tstop,i)
×
2400
        }
2401
        else {        /* Tensors */
2402
          tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = tstop - tt;
×
2403
          if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
×
2404
/*
2405
          We need to:
2406
                1: get pointers to the arguments
2407
                2: reverse the order of the pointers
2408
                3: copy the arguments to safe territory in the new order
2409
                4: copy this new order back in situ.
2410
*/
2411
          if ( arg2 < arg1 ) { n = arg1; arg1 = arg2; arg2 = n; }
×
2412
          if ( arg2 > totarg ) return(0);
×
2413

2414
          num = arg2-arg1+1;
×
2415
          WantAddPointers(num);        /* Guarantees the presence of enough pointers */
×
2416
          f = fun+FUNHEAD; n = 1; i = 0;
×
2417
          while ( n < arg1 ) { n++; f++; }
×
2418
          f1 = f;
×
2419
          while ( n <= arg2 ) { AT.pWorkSpace[AT.pWorkPointer+i++] = f; n++; f++; }
×
2420
          i1 = i-1; i2 = 0;
×
2421
          while ( i1 > i2 ) {
×
2422
                tt = AT.pWorkSpace[AT.pWorkPointer+i1];
×
2423
                AT.pWorkSpace[AT.pWorkPointer+i1] = AT.pWorkSpace[AT.pWorkPointer+i2];
×
2424
                AT.pWorkSpace[AT.pWorkPointer+i2] = tt;
×
2425
                i1--; i2++;
×
2426
          }
2427
          if ( tstop+(f-f1) > AT.WorkTop ) goto OverWork;
×
2428
          f2 = tstop;
2429
          for ( i = 0; i < num; i++ ) { f = AT.pWorkSpace[AT.pWorkPointer+i]; *f2++ = *f++; }
×
2430
          i = f2 - tstop;
×
2431
          NCOPY(f1,tstop,i)
×
2432
        }
2433
        return(0);
2434
OverWork:;
×
2435
        MLOCK(ErrorMessageLock);
×
2436
        MesWork();
×
2437
        MUNLOCK(ErrorMessageLock);
×
2438
        return(-1);
×
2439
}
2440

2441
/*
2442
                 #] RunReverse : 
2443
                 #[ RunDedup :
2444
*/
2445

2446
WORD RunDedup(PHEAD WORD *fun, WORD *args)
81✔
2447
{
2448
        WORD *tt, totarg, *tstop, arg1, arg2, n, i, j,k, *f, *f1, *f2, *fd, *fstart;
81✔
2449
        if ( *args != ARGRANGE ) {
81✔
2450
                MLOCK(ErrorMessageLock);
×
2451
                MesPrint("Illegal range encountered in RunDedup");
×
2452
                MUNLOCK(ErrorMessageLock);
×
2453
                Terminate(-1);
×
2454
        }
2455
        if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
81✔
2456
          tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
72✔
2457
          while ( tt < tstop ) { totarg++; NEXTARG(tt); }
6,189✔
2458
          if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
72✔
2459

2460
          if ( arg2 < arg1 ) { n = arg1; arg1 = arg2; arg2 = n; }
72✔
2461
          if ( arg2 > totarg ) return(0);
72✔
2462

2463
          f = fun+FUNHEAD; n = 1;
2464
          while ( n < arg1 ) { n++; NEXTARG(f) }
78✔
2465
          f1 = f; // fast forward to first element in range
2466
          i = 0; // new argument count
2467
          fstart = f1;
2468

2469
          for (; n <= arg2; n++ ) {
6,171✔
2470
                  f2 = fstart;
2471
                  for ( j = 0; j < i; j++ ) { // check all previous terms
153,324✔
2472
                          fd = f2;
150,261✔
2473
                          NEXTARG(fd)
150,261✔
2474
                          for ( k = 0; k < fd-f2; k++ ) // byte comparison of args
303,474✔
2475
                                  if ( f2[k] != f[k] ) break;
300,438✔
2476

2477
                          if ( k == fd-f2 ) break; // duplicate arg
150,261✔
2478
                          f2 = fd;
147,225✔
2479
                  }
2480

2481
                  if ( j == i ) {
6,099✔
2482
                          // unique factor, copy in situ
2483
                          COPY1ARG(f1,f)
3,156✔
2484
                          i++;
3,063✔
2485
                  } else {
2486
                          NEXTARG(f)
3,036✔
2487
                  }
2488
          }
2489

2490
          // move the terms from after the range
2491
          for (j = n; j <= totarg; j++) {
84✔
2492
                  COPY1ARG(f1,f)
12✔
2493
          }
2494

2495
          fun[1] = f1 - fun; // resize function
72✔
2496
        }
2497
        else {        /* Tensors */
2498
          tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = tstop - tt;
9✔
2499
          if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
9✔
2500

2501
          if ( arg2 < arg1 ) { n = arg1; arg1 = arg2; arg2 = n; }
9✔
2502
          if ( arg2 > totarg ) return(0);
9✔
2503

2504
          f = fun+FUNHEAD;
9✔
2505
          i = arg1; // new argument count
9✔
2506
          n = i;
9✔
2507

2508
          for (; n <= arg2; n++ ) {
72✔
2509
                  for ( j = arg1; j < i; j++ ) { // check all previous terms
150✔
2510
                          if ( f[n-1] == f[j-1] ) break; // duplicate arg
114✔
2511
                  }
2512

2513
                  if ( j == i ) {
63✔
2514
                          // unique factor, copy in situ
2515
                          f[i-1] = f[n-1];
36✔
2516
                          i++;
36✔
2517
                  }
2518
          }
2519

2520
          // move the terms from after the range
2521
          for (j = n; j <= totarg; j++, i++) {
21✔
2522
                  f[i-1] = f[j-1];
12✔
2523
          }
2524

2525
          fun[1] = f + i - 1 - fun; // resize function
9✔
2526
        }
2527
        return(0);
2528
}
2529

2530
/*
2531
                 #] RunDedup : 
2532
                 #[ RunCycle :
2533
*/
2534

2535
WORD RunCycle(PHEAD WORD *fun, WORD *args, WORD *info)
×
2536
{
2537
        WORD *tt, totarg, *tstop, arg1, arg2, n, num, i, j, *f, *f1, *f2, x, ncyc, cc;
×
2538
        if ( *args != ARGRANGE ) {
×
2539
                MLOCK(ErrorMessageLock);
×
2540
                MesPrint("Illegal range encountered in RunCycle");
×
2541
                MUNLOCK(ErrorMessageLock);
×
2542
                Terminate(-1);
×
2543
        }
2544
        ncyc = info[1];
×
2545
        if ( ncyc >= MAXPOSITIVE2 ) { /* $ variable */
×
2546
                ncyc -= MAXPOSITIVE2;
×
2547
                if ( ncyc >= MAXPOSITIVE4 ) {
×
2548
                        ncyc -= MAXPOSITIVE4; /* -$ */
×
2549
                        cc = -1;
×
2550
                }
2551
                else cc = 1;
2552
                ncyc = DolToNumber(BHEAD ncyc);
×
2553
                if ( AN.ErrorInDollar ) {
×
2554
                        MesPrint(" Error in Dollar variable in transform,cycle()=$");
×
2555
                        return(-1);
×
2556
                }
2557
                if ( ncyc >= MAXPOSITIVE4 || ncyc <= -MAXPOSITIVE4 ) {
×
2558
                        MesPrint(" Illegal value from Dollar variable in transform,cycle()=$");
×
2559
                        return(-1);
×
2560
                }
2561
                ncyc *= cc;
×
2562
        }
2563
        if ( functions[fun[0]-FUNCTION].spec != TENSORFUNCTION ) {
×
2564
          tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
×
2565
          while ( tt < tstop ) { totarg++; NEXTARG(tt); }
×
2566
          if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
×
2567
          if ( arg1 > arg2 ) { n = arg1; arg1 = arg2; arg2 = n; }
×
2568
          if ( arg2 > totarg ) return(0);
×
2569
/*
2570
          We need to:
2571
                1: get pointers to the arguments
2572
                2: cycle the pointers
2573
                3: copy the arguments to safe territory in the new order
2574
                4: copy this new order back in situ.
2575
*/
2576
          num = arg2-arg1+1;
×
2577
          WantAddPointers(num);        /* Guarantees the presence of enough pointers */
×
2578
          f = fun+FUNHEAD; n = 1; i = 0;
×
2579
          while ( n < arg1 ) { n++; NEXTARG(f) }
×
2580
          f1 = f;
×
2581
          while ( n <= arg2 ) { AT.pWorkSpace[AT.pWorkPointer+i++] = f; n++; NEXTARG(f) }
×
2582
/*
2583
          Now the cycle(s). First minimize the number of cycles.
2584
*/
2585
          x = ncyc;
×
2586
          if ( x >= i ) {
×
2587
                x %= i;
×
2588
                if ( x > i/2 ) x -= i;
×
2589
          }
2590
          else if ( x <= -i ) {
×
2591
                x = -((-x) % i);
×
2592
                if ( x <= -i/2 ) x += i;
×
2593
          }
2594
          while ( x ) {
×
2595
                if ( x > 0 ) {
×
2596
                        tt = AT.pWorkSpace[AT.pWorkPointer+i-1];
×
2597
                        for ( j = i-1; j > 0; j-- )
×
2598
                                AT.pWorkSpace[AT.pWorkPointer+j] = AT.pWorkSpace[AT.pWorkPointer+j-1];
×
2599
                        AT.pWorkSpace[AT.pWorkPointer] = tt;
×
2600
                        x--;
×
2601
                }
2602
                else {
2603
                        tt = AT.pWorkSpace[AT.pWorkPointer];
×
2604
                        for ( j = 1; j < i; j++ )
×
2605
                                AT.pWorkSpace[AT.pWorkPointer+j-1] = AT.pWorkSpace[AT.pWorkPointer+j];
×
2606
                        AT.pWorkSpace[AT.pWorkPointer+j-1] = tt;
×
2607
                        x++;
×
2608
                }
2609
          }
2610
/*
2611
          And the final cleanup
2612
*/
2613
          if ( tstop+(f-f1) > AT.WorkTop ) goto OverWork;
×
2614
          f2 = tstop;
2615
          for ( i = 0; i < num; i++ ) { f = AT.pWorkSpace[AT.pWorkPointer+i]; COPY1ARG(f2,f) }
×
2616
          i = f2 - tstop;
×
2617
          NCOPY(f1,tstop,i)
×
2618
        }
2619
        else {        /* Tensors */
2620
          tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = tstop - tt;
×
2621
          if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
×
2622
          if ( arg1 > arg2 ) { n = arg1; arg1 = arg2; arg2 = n; }
×
2623
          if ( arg2 > totarg ) return(0);
×
2624
/*
2625
          We need to:
2626
                1: get pointers to the arguments
2627
                2: cycle the pointers
2628
                3: copy the arguments to safe territory in the new order
2629
                4: copy this new order back in situ.
2630
*/
2631
          num = arg2-arg1+1;
×
2632
          WantAddPointers(num);        /* Guarantees the presence of enough pointers */
×
2633
          f = fun+FUNHEAD; n = 1; i = 0;
×
2634
          while ( n < arg1 ) { n++; f++; }
×
2635
          f1 = f;
×
2636
          while ( n <= arg2 ) { AT.pWorkSpace[AT.pWorkPointer+i++] = f; n++; f++; }
×
2637
/*
2638
          Now the cycle(s). First minimize the number of cycles.
2639
*/
2640
          x = ncyc;
×
2641
          if ( x >= i ) {
×
2642
                x %= i;
×
2643
                if ( x > i/2 ) x -= i;
×
2644
          }
2645
          else if ( x <= -i ) {
×
2646
                x = -((-x) % i);
×
2647
                if ( x <= -i/2 ) x += i;
×
2648
          }
2649
          while ( x ) {
×
2650
                if ( x > 0 ) {
×
2651
                        tt = AT.pWorkSpace[AT.pWorkPointer+i-1];
×
2652
                        for ( j = i-1; j > 0; j-- )
×
2653
                                AT.pWorkSpace[AT.pWorkPointer+j] = AT.pWorkSpace[AT.pWorkPointer+j-1];
×
2654
                        AT.pWorkSpace[AT.pWorkPointer] = tt;
×
2655
                        x--;
×
2656
                }
2657
                else {
2658
                        tt = AT.pWorkSpace[AT.pWorkPointer];
×
2659
                        for ( j = 1; j < i; j++ )
×
2660
                                AT.pWorkSpace[AT.pWorkPointer+j-1] = AT.pWorkSpace[AT.pWorkPointer+j];
×
2661
                        AT.pWorkSpace[AT.pWorkPointer+j-1] = tt;
×
2662
                        x++;
×
2663
                }
2664
          }
2665
/*
2666
          And the final cleanup
2667
*/
2668
          if ( tstop+(f-f1) > AT.WorkTop ) goto OverWork;
×
2669
          f2 = tstop;
2670
          for ( i = 0; i < num; i++ ) { f = AT.pWorkSpace[AT.pWorkPointer+i]; *f2++ = *f++; }
×
2671
          i = f2 - tstop;
×
2672
          NCOPY(f1,tstop,i)
×
2673
        }
2674
        return(0);
2675
OverWork:;
×
2676
        MLOCK(ErrorMessageLock);
×
2677
        MesWork();
×
2678
        MUNLOCK(ErrorMessageLock);
×
2679
        return(-1);
×
2680
}
2681

2682
/*
2683
                 #] RunCycle : 
2684
                 #[ RunAddArg :
2685
*/
2686

2687
WORD RunAddArg(PHEAD WORD *fun, WORD *args)
27✔
2688
{
2689
        WORD *tt, totarg, *tstop, arg1, arg2, n, num, *f, *f1, *f2;
27✔
2690
        WORD scribble[10+ARGHEAD];
27✔
2691
        LONG space;
27✔
2692
        if ( *args != ARGRANGE ) {
27✔
2693
                MLOCK(ErrorMessageLock);
×
2694
                MesPrint("Illegal range encountered in RunAddArg");
×
2695
                MUNLOCK(ErrorMessageLock);
×
2696
                Terminate(-1);
×
2697
        }
2698
        if ( functions[fun[0]-FUNCTION].spec == TENSORFUNCTION ) {
27✔
2699
                MLOCK(ErrorMessageLock);
×
2700
                MesPrint("Illegal attempt to add arguments of a tensor in AddArg");
×
2701
                MUNLOCK(ErrorMessageLock);
×
2702
                Terminate(-1);
×
2703
        }
2704
        tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
27✔
2705
        while ( tt < tstop ) { totarg++; NEXTARG(tt); }
249✔
2706
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
27✔
2707
/*
2708
        We need to:
2709
                1: establish that we actually need to add something
2710
                2: start a sort
2711
                3: if needed, convert arguments to long arguments
2712
                4: send (terms in) argument to StoreTerm
2713
                5: EndSort and copy the result back into the function
2714
        Note that the function is in the workspace, above the term and no
2715
        relevant information is trailing it.
2716
*/
2717
        if ( arg2 < arg1 ) { n = arg1; arg1 = arg2; arg2 = n; }
27✔
2718
        if ( arg2 > totarg ) return(0);
27✔
2719
        num = arg2-arg1+1;
27✔
2720
        if ( num == 1 ) return(0);
27✔
2721
        f = fun+FUNHEAD; n = 1;
2722
        while ( n < arg1 ) { n++; NEXTARG(f) }
75✔
2723
        f1 = f;
27✔
2724
        NewSort(BHEAD0);
27✔
2725
        while ( n <= arg2 ) {
105✔
2726
                if ( *f > 0 ) {
78✔
2727
                        f2 = f + *f; f += ARGHEAD;
×
2728
                        while ( f < f2 ) { StoreTerm(BHEAD f); f += *f; }
×
2729
                }
2730
                else if ( *f == -SNUMBER && f[1] == 0 ) {
78✔
2731
                        f+= 2;
×
2732
                }
2733
                else {
2734
                        ToGeneral(f,scribble,1);
78✔
2735
                        StoreTerm(BHEAD scribble);
78✔
2736
                        NEXTARG(f);
78✔
2737
                }
2738
                n++;
78✔
2739
        }
2740
        if ( EndSort(BHEAD tstop+ARGHEAD,1) ) return(-1);
27✔
2741
        num = 0;
2742
        f2 = tstop+ARGHEAD;
2743
        while ( *f2 ) { f2 += *f2; num++; }
51✔
2744
        *tstop = f2-tstop;
27✔
2745
        for ( n = 1; n < ARGHEAD; n++ ) tstop[n] = 0;
54✔
2746
        if ( num == 1 && ToFast(tstop,tstop) == 1 ) {
27✔
2747
                f2 = tstop; NEXTARG(f2);
24✔
2748
        }
2749
        if ( *tstop == ARGHEAD ) {
27✔
2750
                *tstop = -SNUMBER; tstop[1] = 0;
3✔
2751
                f2 = tstop+2;
3✔
2752
        }
2753
/*
2754
        Copy the trailing arguments after the new argument, then copy the whole back.
2755
*/
2756
        while ( f < tstop ) *f2++ = *f++;
219✔
2757
        while ( f < f2 ) *f1++ = *f++;
273✔
2758
        space = f1 - fun;
27✔
2759
        if ( (space+8)*sizeof(WORD) > (UWORD)AM.MaxTer ) {
27✔
2760
                MLOCK(ErrorMessageLock);
×
2761
                MesWork();
×
2762
                MUNLOCK(ErrorMessageLock);
×
2763
                return(-1);
×
2764
        }
2765
        fun[1] = (WORD)space;
27✔
2766
        return(0);
27✔
2767
}
2768

2769
/*
2770
                 #] RunAddArg : 
2771
                 #[ RunMulArg :
2772
*/
2773

2774
WORD RunMulArg(PHEAD WORD *fun, WORD *args)
33✔
2775
{
2776
        WORD *t, totarg, *tstop, arg1, arg2, n, *f, nb, *m, i, *w;
33✔
2777
        WORD *scratch, argbuf[20], argsize, *where, *newterm;
33✔
2778
        LONG oldcpointer_pos;
33✔
2779
        CBUF *C = cbuf + AT.ebufnum;
33✔
2780
        if ( *args != ARGRANGE ) {
33✔
2781
                MLOCK(ErrorMessageLock);
×
2782
                MesPrint("Illegal range encountered in RunMulArg");
×
2783
                MUNLOCK(ErrorMessageLock);
×
2784
                Terminate(-1);
×
2785
        }
2786
        if ( functions[fun[0]-FUNCTION].spec == TENSORFUNCTION ) {
33✔
2787
                MLOCK(ErrorMessageLock);
×
2788
                MesPrint("Illegal attempt to multiply arguments of a tensor in MulArg");
×
2789
                MUNLOCK(ErrorMessageLock);
×
2790
                Terminate(-1);
×
2791
        }
2792
        t = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
33✔
2793
        while ( t < tstop ) { totarg++; NEXTARG(t); }
300✔
2794
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
33✔
2795
        if ( arg2 < arg1 ) { n = arg1; arg1 = arg2; arg2 = n; }
33✔
2796
        if ( arg1 > totarg ) return(0);
33✔
2797
        if ( arg2 < 1 ) return(0);
33✔
2798
        if ( arg1 < 1 ) arg1 = 1;
33✔
2799
        if ( arg2 > totarg ) arg2 = totarg;
33✔
2800
        if ( arg1 == arg2 ) return(0);
33✔
2801
/*
2802
        Now we move the arguments to a compiler buffer
2803
        Then we create a term in the workspace that is the product of
2804
        subexpression pointers to the objects in the compiler buffer.
2805
        Next we let Generator work out that term.
2806
        Finally we pick up the results from EndSort and put it in the function.
2807
*/
2808
        f = fun+FUNHEAD; n = 1;
2809
        while ( n < arg1 ) { n++; NEXTARG(f) }
81✔
2810
        t = f;
33✔
2811
        if ( fun >= AT.WorkSpace && fun < AT.WorkTop ) {
33✔
2812
                if ( AT.WorkPointer < fun+fun[1] ) AT.WorkPointer = fun+fun[1];
33✔
2813
        }
2814
        scratch = AT.WorkPointer;
33✔
2815
        w = scratch+1;
33✔
2816
        oldcpointer_pos = C->Pointer-C->Buffer;
33✔
2817
        nb = C->numrhs;
33✔
2818
        while ( n <= arg2 ) {
33✔
2819
                if ( *t > 0 ) {
123✔
2820
                        argsize = *t - ARGHEAD; where = t + ARGHEAD; t += *t;
51✔
2821
                }
2822
                else if ( *t <= -FUNCTION ) {
72✔
2823
                        argbuf[0] = FUNHEAD+4; argbuf[1] = -*t++; argbuf[2] = FUNHEAD;
×
2824
                        for ( i = 2; i < FUNHEAD; i++ ) argbuf[i+1] = 0;
×
2825
                        argbuf[FUNHEAD+1] = 1;
×
2826
                        argbuf[FUNHEAD+2] = 1;
×
2827
                        argbuf[FUNHEAD+3] = 3;
×
2828
                        argsize = argbuf[0];
×
2829
                        where = argbuf;
×
2830
                }
2831
                else if ( *t == -SYMBOL ) {
72✔
2832
                        argbuf[0] = 8; argbuf[1] = SYMBOL; argbuf[2] = 4;
×
2833
                        argbuf[3] = t[1]; argbuf[4] = 1;
×
2834
                        argbuf[5] = 1; argbuf[6] = 1; argbuf[7] = 3;
×
2835
                        argsize = 8; t += 2;
×
2836
                        where = argbuf;
×
2837
                }
2838
                else if ( *t == -VECTOR || *t == -MINVECTOR ) {
2839
                        argbuf[0] = 7; argbuf[1] = INDEX; argbuf[2] = 3;
×
2840
                        argbuf[3] = t[1];
×
2841
                        argbuf[4] = 1; argbuf[5] = 1;
×
2842
                        if ( *t == -MINVECTOR ) argbuf[6] = -3;
×
2843
                        else argbuf[6] = 3;
×
2844
                        argsize = 7; t += 2;
×
2845
                        where = argbuf;
×
2846
                }
2847
                else if ( *t == -INDEX ) {
2848
                        argbuf[0] = 7; argbuf[1] = INDEX; argbuf[2] = 3;
×
2849
                        argbuf[3] = t[1];
×
2850
                        argbuf[4] = 1; argbuf[5] = 1; argbuf[6] = 3;
×
2851
                        argsize = 7; t += 2;
×
2852
                        where = argbuf;
×
2853
                }
2854
                else if ( *t == -SNUMBER ) {
2855
                        if ( t[1] < 0 ) {
72✔
2856
                                argbuf[0] = 4; argbuf[1] = -t[1]; argbuf[2] = 1; argbuf[3] = -3;
×
2857
                        }
2858
                        else {
2859
                                argbuf[0] = 4; argbuf[1] = t[1]; argbuf[2] = 1; argbuf[3] = 3;
72✔
2860
                        }
2861
                        argsize = 4; t += 2;
72✔
2862
                        where = argbuf;
72✔
2863
                }
2864
                else {
2865
                        /* unreachable */
2866
                        return(1);
2867
                }
2868
/*
2869
                Now add the argbuf to AT.ebufnum
2870
*/
2871
                m = AddRHS(AT.ebufnum,1);
123✔
2872
                while ( (m + argsize + 10) > C->Top ) m = DoubleCbuffer(AT.ebufnum,m,17);
126✔
2873
                for ( i = 0; i < argsize; i++ ) m[i] = where[i];
2,547✔
2874
                m[i] = 0;
123✔
2875
                C->Pointer = m + i + 1;
123✔
2876
                n++;
123✔
2877
                *w++ = SUBEXPRESSION; *w++ = SUBEXPSIZE; *w++ = C->numrhs; *w++ = 1;
123✔
2878
                *w++ = AT.ebufnum; FILLSUB(w);
156✔
2879
        }
2880
        *w++ = 1; *w++ = 1; *w++ = 3;
33✔
2881
        *scratch = w-scratch;
33✔
2882
        AT.WorkPointer = w;
33✔
2883
        NewSort(BHEAD0);
33✔
2884
        Generator(BHEAD scratch,AR.Cnumlhs);
33✔
2885
        newterm = AT.WorkPointer;
33✔
2886
        EndSort(BHEAD newterm+ARGHEAD,1);
33✔
2887
        C->Pointer = C->Buffer+oldcpointer_pos;
33✔
2888
        C->numrhs = nb;
33✔
2889
        w = newterm+ARGHEAD; while ( *w ) w += *w;
9,300✔
2890
        *newterm = w-newterm; newterm[1] = 0;
33✔
2891
        if ( ToFast(newterm,newterm) ) {
33✔
2892
                if ( *newterm <= -FUNCTION ) w = newterm+1;
24✔
2893
                else w = newterm+2;
2894
        }
2895
        while ( t < tstop ) *w++ = *t++;
225✔
2896
        i = w - newterm;
33✔
2897
        t = newterm; NCOPY(f,t,i);
133,029✔
2898
        fun[1] = f-fun;
33✔
2899
        AT.WorkPointer = scratch;
33✔
2900
        if ( AT.WorkPointer > AT.WorkSpace && AT.WorkPointer < f ) AT.WorkPointer = f;
33✔
2901
        return(0);
2902
}
2903

2904
/*
2905
                 #] RunMulArg : 
2906
                 #[ RunIsLyndon :
2907

2908
                Determines whether the range constitutes a Lyndon word.
2909
                The two cases of ordering are distinguished by the order of
2910
                the numbers of the arguments in the range.
2911
*/
2912

2913
WORD RunIsLyndon(PHEAD WORD *fun, WORD *args, int par)
×
2914
{
2915
        WORD *tt, totarg, *tstop, arg1, arg2, arg, num, *f, n, i;
×
2916
/*        WORD *f1; */
2917
        WORD sign, i1, i2, retval;
×
2918
        if ( fun[0] <= GAMMASEVEN && fun[0] >= GAMMA ) return(0);
×
2919
        if ( *args != ARGRANGE ) {
×
2920
                MLOCK(ErrorMessageLock);
×
2921
                MesPrint("Illegal range encountered in RunIsLyndon");
×
2922
                MUNLOCK(ErrorMessageLock);
×
2923
                Terminate(-1);
×
2924
        }
2925
        tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
×
2926
        while ( tt < tstop ) { totarg++; NEXTARG(tt); }
×
2927
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
×
2928
        if ( arg1 > totarg || arg2 > totarg ) return(-1);
×
2929
/*
2930
        Now make a list of the relevant arguments.
2931
*/
2932
        if ( arg1 == arg2 ) return(1);
×
2933
        if ( arg2 < arg1 ) {        /* greater, rather than smaller */
×
2934
                arg = arg1; arg1 = arg2; arg2 = arg; sign = 1;
×
2935
        }
2936
        else sign = 0;
2937

2938
        num = arg2-arg1+1;
×
2939
        WantAddPointers(num);        /* Guarantees the presence of enough pointers */
×
2940
        f = fun+FUNHEAD; n = 1; i = 0;
×
2941
        while ( n < arg1 ) { n++; NEXTARG(f) }
×
2942
/*        f1 = f; */
2943
        while ( n <= arg2 ) { AT.pWorkSpace[AT.pWorkPointer+i++] = f; n++; NEXTARG(f) }
×
2944
/*
2945
        If sign == 1 we should alter the order of the pointers first
2946
*/
2947
        if ( sign ) {
×
2948
                i1 = i-1; i2 = 0;
×
2949
                while ( i1 > i2 ) {
×
2950
                        tt = AT.pWorkSpace[AT.pWorkPointer+i1];
×
2951
                        AT.pWorkSpace[AT.pWorkPointer+i1] = AT.pWorkSpace[AT.pWorkPointer+i2];
×
2952
                        AT.pWorkSpace[AT.pWorkPointer+i2] = tt;
×
2953
                        i1--; i2++;
×
2954
                }
2955
        }
2956
/*
2957
        The argument range is from f1 to f and the num pointers to the arguments
2958
        are in AT.pWorkSpace[AT.pWorkPointer] to AT.pWorkSpace[AT.pWorkPointer+num-1]
2959
*/
2960
        for ( i1 = 1; i1 < num; i1++ ) {
×
2961
                retval = par * CompArg(AT.pWorkSpace[AT.pWorkPointer+i1],
×
2962
                                                        AT.pWorkSpace[AT.pWorkPointer]);
×
2963
                if ( retval > 0 ) continue;
×
2964
                if ( retval < 0 ) return(0);
×
2965
        for ( i2 = 1; i2 < num; i2++ ) {
×
2966
                        retval = par * CompArg(AT.pWorkSpace[AT.pWorkPointer+(i1+i2)%num],
×
2967
                                                        AT.pWorkSpace[AT.pWorkPointer+i2]);
×
2968
                        if ( retval < 0 ) return(0);
×
2969
                        if ( retval > 0 ) goto nexti1;
×
2970
                }
2971
/*
2972
                If we come here the sequence is not unique.
2973
*/
2974
                return(0);
2975
nexti1:;
×
2976
        }
2977
        return(1);
2978
}
2979

2980
/*
2981
                 #] RunIsLyndon : 
2982
                 #[ RunToLyndon :
2983

2984
                Determines whether the range constitutes a Lyndon word.
2985
                If not, we rotate it to a Lyndon word. If this is not possible
2986
                we return the noLyndon condition.
2987
                The two cases of ordering are distinguished by the order of
2988
                the numbers of the arguments in the range.
2989
*/
2990

2991
WORD RunToLyndon(PHEAD WORD *fun, WORD *args, int par)
×
2992
{
2993
        WORD *tt, totarg, *tstop, arg1, arg2, arg, num, *f, *f1, *f2, n, i;
×
2994
        WORD sign, i1, i2, retval, unique;
×
2995
        if ( fun[0] <= GAMMASEVEN && fun[0] >= GAMMA ) return(0);
×
2996
        if ( *args != ARGRANGE ) {
×
2997
                MLOCK(ErrorMessageLock);
×
2998
                MesPrint("Illegal range encountered in RunToLyndon");
×
2999
                MUNLOCK(ErrorMessageLock);
×
3000
                Terminate(-1);
×
3001
        }
3002
        tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
×
3003
        while ( tt < tstop ) { totarg++; NEXTARG(tt); }
×
3004
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
×
3005
        if ( arg1 > totarg || arg2 > totarg ) return(-1);
×
3006
/*
3007
        Now make a list of the relevant arguments.
3008
*/
3009
        if ( arg1 == arg2 ) return(1);
×
3010
        if ( arg2 < arg1 ) {        /* greater, rather than smaller */
×
3011
                arg = arg1; arg1 = arg2; arg2 = arg; sign = 1;
×
3012
        }
3013
        else sign = 0;
3014

3015
        num = arg2-arg1+1;
×
3016
        WantAddPointers((2*num));        /* Guarantees the presence of enough pointers */
×
3017
        f = fun+FUNHEAD; n = 1; i = 0;
×
3018
        while ( n < arg1 ) { n++; NEXTARG(f) }
×
3019
        f1 = f;
×
3020
        while ( n <= arg2 ) { AT.pWorkSpace[AT.pWorkPointer+i++] = f; n++; NEXTARG(f) }
×
3021
/*
3022
        If sign == 1 we should alter the order of the pointers first
3023
*/
3024
        if ( sign ) {
×
3025
                i1 = i-1; i2 = 0;
×
3026
                while ( i1 > i2 ) {
×
3027
                        tt = AT.pWorkSpace[AT.pWorkPointer+i1];
×
3028
                        AT.pWorkSpace[AT.pWorkPointer+i1] = AT.pWorkSpace[AT.pWorkPointer+i2];
×
3029
                        AT.pWorkSpace[AT.pWorkPointer+i2] = tt;
×
3030
                        i1--; i2++;
×
3031
                }
3032
        }
3033
/*
3034
        The argument range is from f1 to f and the num pointers to the arguments
3035
        are in AT.pWorkSpace[AT.pWorkPointer] to AT.pWorkSpace[AT.pWorkPointer+num-1]
3036
*/
3037
        unique = 1;
3038
        for ( i1 = 1; i1 < num; i1++ ) {
×
3039
                retval = par * CompArg(AT.pWorkSpace[AT.pWorkPointer+i1],
×
3040
                                                        AT.pWorkSpace[AT.pWorkPointer]);
×
3041
                if ( retval > 0 ) continue;
×
3042
                if ( retval < 0 ) {
×
3043
Rotate:;
×
3044
/*
3045
                        Rotate so that i1 becomes the zero element. Then start again.
3046
*/
3047
                        for ( i2 = 0; i2 < num; i2++ ) {
×
3048
                                AT.pWorkSpace[AT.pWorkPointer+num+i2] =
×
3049
                                        AT.pWorkSpace[AT.pWorkPointer+(i1+i2)%num];
×
3050
                        }
3051
                        for ( i2 = 0; i2 < num; i2++ ) {
×
3052
                                AT.pWorkSpace[AT.pWorkPointer+i2] =
×
3053
                                        AT.pWorkSpace[AT.pWorkPointer+i2+num];
×
3054
                        }
3055
                        i1 = 0;
×
3056
                        goto nexti1;
×
3057
                }
3058
        for ( i2 = 1; i2 < num; i2++ ) {
×
3059
                        retval = par * CompArg(AT.pWorkSpace[AT.pWorkPointer+(i1+i2)%num],
×
3060
                                                        AT.pWorkSpace[AT.pWorkPointer+i2]);
×
3061
                        if ( retval < 0 ) goto Rotate;
×
3062
                        if ( retval > 0 ) goto nexti1;
×
3063
                }
3064
/*
3065
                If we come here the sequence is not unique.
3066
*/
3067
                unique = 0;
3068
nexti1:;
×
3069
        }
3070
        if ( sign ) {
×
3071
                i1 = i-1; i2 = 0;
×
3072
                while ( i1 > i2 ) {
×
3073
                        tt = AT.pWorkSpace[AT.pWorkPointer+i1];
×
3074
                        AT.pWorkSpace[AT.pWorkPointer+i1] = AT.pWorkSpace[AT.pWorkPointer+i2];
×
3075
                        AT.pWorkSpace[AT.pWorkPointer+i2] = tt;
×
3076
                        i1--; i2++;
×
3077
                }
3078
        }
3079
/*
3080
        Now rewrite the arguments into the proper order
3081
*/
3082
        if ( tstop+(f-f1) > AT.WorkTop ) goto OverWork;
×
3083
        f2 = tstop;
3084
        for ( i = 0; i < num; i++ ) { f = AT.pWorkSpace[AT.pWorkPointer+i]; COPY1ARG(f2,f) }
×
3085
        i = f2 - tstop;
×
3086
        NCOPY(f1,tstop,i)
×
3087
/*
3088
        The return value indicates whether we have a Lyndon word
3089
*/
3090
        return(unique);
3091
OverWork:;
×
3092
        MLOCK(ErrorMessageLock);
×
3093
        MesWork();
×
3094
        MUNLOCK(ErrorMessageLock);
×
3095
        return(-2);
×
3096
}
3097

3098
/*
3099
                 #] RunToLyndon : 
3100
                 #[ RunDropArg :
3101
*/
3102

3103
WORD RunDropArg(PHEAD WORD *fun, WORD *args)
24✔
3104
{
3105
        WORD *t, *tstop, *f, totarg, arg1, arg2, n;
24✔
3106

3107
        t = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
24✔
3108
        while ( t < tstop ) { totarg++; NEXTARG(t); }
240✔
3109
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
24✔
3110
        if ( arg2 < arg1 ) { n = arg1; arg1 = arg2; arg2 = n; }
24✔
3111
        if ( arg1 > totarg ) return(0);
24✔
3112
        if ( arg2 < 1 ) return(0);
24✔
3113
        if ( arg1 < 1 ) arg1 = 1;
24✔
3114
        if ( arg2 > totarg ) arg2 = totarg;
24✔
3115
        f = fun+FUNHEAD; n = 1;
24✔
3116
        while ( n < arg1 ) { n++; NEXTARG(f) }
72✔
3117
        t = f;
3118
        while ( n <= arg2 ) { n++; NEXTARG(t) }
96✔
3119
        while ( t < tstop ) *f++ = *t++;
216✔
3120
        fun[1] = f-fun;
24✔
3121
        return(0);
24✔
3122
}
3123

3124
/*
3125
                 #] RunDropArg : 
3126
                 #[ RunSelectArg :
3127
*/
3128

3129
WORD RunSelectArg(PHEAD WORD *fun, WORD *args)
24✔
3130
{
3131
        WORD *t, *tstop, *f, *tt, totarg, arg1, arg2, n;
24✔
3132

3133
        t = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
24✔
3134
        while ( t < tstop ) { totarg++; NEXTARG(t); }
240✔
3135
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
24✔
3136
        if ( arg2 < arg1 ) { n = arg1; arg1 = arg2; arg2 = n; }
24✔
3137
        if ( arg1 > totarg ) return(0);
24✔
3138
        if ( arg2 < 1 ) return(0);
24✔
3139
        if ( arg1 < 1 ) arg1 = 1;
24✔
3140
        if ( arg2 > totarg ) arg2 = totarg;
24✔
3141
        f = fun+FUNHEAD; n = 1; t = f;
24✔
3142
        while ( n < arg1 ) { n++; NEXTARG(t) }
72✔
3143
        while ( n <= arg2 ) {
96✔
3144
                tt = t; NEXTARG(tt)
72✔
3145
                while ( t < tt ) *f++ = *t++;
216✔
3146
                n++;
72✔
3147
        }
3148
        fun[1] = f-fun;
24✔
3149
        return(0);
24✔
3150
}
3151

3152
/*
3153
                 #] RunSelectArg : 
3154
                 #[ RunZtoHArg :
3155
*/
3156

3157
WORD RunZtoHArg(PHEAD WORD *fun, WORD *args)
×
3158
{
3159
        WORD *tt, totarg, *tstop, arg1, arg2, n, i, *f, *f1, sign = 0;
×
3160
        WORD *t, *t1, *t2, *t3;
×
3161
        if ( *args != ARGRANGE ) {
×
3162
                MLOCK(ErrorMessageLock);
×
3163
                MesPrint("Illegal range encountered in RunZtoHArg.");
×
3164
                MUNLOCK(ErrorMessageLock);
×
3165
                Terminate(-1);
×
3166
        }
3167
        if ( functions[fun[0]-FUNCTION].spec != 0 ) {
×
3168
                MLOCK(ErrorMessageLock);
×
3169
                MesPrint("The ZtoH transformation can only be executed on regular functions with nonzero integer arguments.");
×
3170
                MUNLOCK(ErrorMessageLock);
×
3171
                Terminate(-1);
×
3172
        }
3173
        tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
×
3174
        while ( tt < tstop ) { totarg++; NEXTARG(tt); }
×
3175
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
×
3176
/*
3177
        Check the arguments. Should be -SNUMBER x!=0
3178
*/
3179
        f = fun+FUNHEAD; n = 1;
3180
        while ( n < arg1 ) { n++; NEXTARG(f) }
×
3181
        f1 = f;
×
3182
        for ( i = arg1; i <= arg2; i++, f += 2 ) {
×
3183
                if ( *f != -SNUMBER || f[1] == 0 ) return(-1);
×
3184
        }
3185
/*
3186
        Now we need a copy. 
3187
*/
3188
        t = f1; t1 = t2 = tt = TermMalloc("RunZtoHArg");
×
3189
        while ( t < f ) { *t1++ = *t++; *t1++ = *t++; }
×
3190
        t = f1; 
3191
        while ( t2 < t1 ) {
×
3192
                t += 2;
×
3193
                if ( t2[1] < 0 ) {
×
3194
                        t3 = t;
3195
                        while ( t3 < f ) { t3[1] = -t3[1]; t3 += 2; }
×
3196
                }
3197
                t2 += 2;
×
3198
        }
3199
        TermFree(tt,"RunZtoHArg");
×
3200
/*
3201
        Now the overall sign.
3202
*/
3203
        while ( f1 < f ) { if ( f1[1] < 0 ) sign = 1-sign; f1 += 2; }
×
3204
        return(sign);
3205
}
3206

3207
/*
3208
                 #] RunZtoHArg : 
3209
                 #[ RunHtoZArg :
3210
*/
3211

3212
WORD RunHtoZArg(PHEAD WORD *fun, WORD *args)
×
3213
{
3214
        WORD *tt, totarg, *tstop, arg1, arg2, n, i, *f, *f1, *f2, sign = 0;
×
3215
        WORD *t, *t1, *t2;
×
3216
        if ( *args != ARGRANGE ) {
×
3217
                MLOCK(ErrorMessageLock);
×
3218
                MesPrint("Illegal range encountered in RunZtoHArg.");
×
3219
                MUNLOCK(ErrorMessageLock);
×
3220
                Terminate(-1);
×
3221
        }
3222
        if ( functions[fun[0]-FUNCTION].spec != 0 ) {
×
3223
                MLOCK(ErrorMessageLock);
×
3224
                MesPrint("The HtoZ transformation can only be executed on regular functions with nonzero integer arguments.");
×
3225
                MUNLOCK(ErrorMessageLock);
×
3226
                Terminate(-1);
×
3227
        }
3228
        tt = fun+FUNHEAD; tstop = fun+fun[1]; totarg = 0;
×
3229
        while ( tt < tstop ) { totarg++; NEXTARG(tt); }
×
3230
        if ( FindRange(BHEAD args,&arg1,&arg2,totarg) ) return(-1);
×
3231
/*
3232
        Check the arguments. Should be -SNUMBER x!=0
3233
*/
3234
        f = fun+FUNHEAD; n = 1;
3235
        while ( n < arg1 ) { n++; NEXTARG(f) }
×
3236
        f2 = f1 = f;
×
3237
        for ( i = arg1; i <= arg2; i++, f += 2 ) {
×
3238
                if ( *f != -SNUMBER || f[1] == 0 ) return(-1);
×
3239
        }
3240
/*
3241
        First the overall sign.
3242
*/
3243
        while ( f2 < f ) { if ( f2[1] < 0 ) sign = 1-sign; f2 += 2; }
×
3244
/*
3245
        Now we need a copy. 
3246
*/
3247
        t = f1; t1 = tt = TermMalloc("RunHtoZArg");
×
3248
        while ( t < f ) { *t1++ = *t++; *t1++ = *t++; }
×
3249
/*
3250
        Now the transformation.
3251
*/
3252
        t = f1; t2 = tt + 2;
×
3253
        while ( t2 < t1 ) {
×
3254
                t += 2;
×
3255
                if ( t2[-1] < 0 ) t[1] = -t[1];
×
3256
                t2 += 2;
×
3257
        }
3258
        TermFree(tt,"RunHtoZArg");
×
3259
        return(sign);
×
3260
}
3261

3262
/*
3263
                 #] RunHtoZArg : 
3264
                 #[ TestArgNum :
3265

3266
                Looks whether argument n is contained in any of the ranges
3267
                specified in args. Args contains objects of the types
3268
                        ALLARGS
3269
                        NUMARG,num
3270
                        ARGRANGE,num1,num2
3271
                The object MAKEARGS,num1,num2 is skipped
3272
                Any other object terminates the range specifications.
3273

3274
                Currently only ARGRANGE is used (10-may-2016)
3275
*/
3276

3277
int TestArgNum(int n, int totarg, WORD *args)
78✔
3278
{
3279
        GETIDENTITY
52✔
3280
        WORD x1, x2;
78✔
3281
        for(;;) {
78✔
3282
                switch ( *args ) {
78✔
3283
                        case ALLARGS:
3284
                                return(1);
3285
                        case NUMARG:
×
3286
                                if ( n == args[1] ) return(1);
×
3287
                                if ( args[1] >= MAXPOSITIVE4 ) {
×
3288
                                        x1 = args[1]-MAXPOSITIVE4;
×
3289
                                        if ( totarg-x1 == n ) return(1);
×
3290
                                }
3291
                                args += 2;
×
3292
                                break;
×
3293
                        case ARGRANGE:
78✔
3294
                                if ( args[1] >= MAXPOSITIVE2 ) {
78✔
3295
                                        x1 = args[1] - MAXPOSITIVE2;
×
3296
                                        if ( x1 > MAXPOSITIVE4 ) {
×
3297
                                                x1 = x1 - MAXPOSITIVE4;
×
3298
                                                x1 = DolToNumber(BHEAD x1);
×
3299
                                                x1 = totarg - x1;
×
3300
                                        }
3301
                                        else {
3302
                                                x1 = DolToNumber(BHEAD x1);
×
3303
                                        }
3304
                                }
3305
                                else if ( args[1] >= MAXPOSITIVE4 ) {
78✔
3306
                                        x1 = totarg-(args[1]-MAXPOSITIVE4);
×
3307
                                }
3308
                                else x1 = args[1];
3309
                                if ( args[2] >= MAXPOSITIVE2 ) {
78✔
3310
                                        x2 = args[2] - MAXPOSITIVE2;
×
3311
                                        if ( x2 > MAXPOSITIVE4 ) {
×
3312
                                                x2 = x2 - MAXPOSITIVE4;
×
3313
                                                x2 = DolToNumber(BHEAD x2);
×
3314
                                                x2 = totarg - x2;
×
3315
                                        }
3316
                                        else {
3317
                                                x2 = DolToNumber(BHEAD x2);
×
3318
                                        }
3319
                                }
3320
                                else if ( args[2] >= MAXPOSITIVE4 ) {
78✔
3321
                                        x2 = totarg-(args[2]-MAXPOSITIVE4);
78✔
3322
                                }
3323
                                else x2 = args[2];
3324
                                if ( x1 >= x2 ) {
78✔
3325
                                        if ( n >= x2 && n <= x1 ) return(1);
×
3326
                                }
3327
                                else {
3328
                                        if ( n >= x1 && n <= x2 ) return(1);
78✔
3329
                                }
3330
                                args += 3;
×
3331
                                break;
×
3332
                        case MAKEARGS:
×
3333
                                args += 3;
×
3334
                                break;
×
3335
                        default:
×
3336
                                return(0);
×
3337
                }
3338
        }
3339
}
3340

3341
/*
3342
                 #] TestArgNum : 
3343
                 #[ PutArgInScratch :
3344
*/
3345

3346
WORD PutArgInScratch(WORD *arg,UWORD *scrat)
60✔
3347
{
3348
        WORD size, *t, i;
60✔
3349
        if ( *arg == -SNUMBER ) {
60✔
3350
                scrat[0] = ABS(arg[1]);
60✔
3351
                if ( arg[1] < 0 ) size = -1;
60✔
3352
                else              size =  1;
60✔
3353
        }
3354
        else {
3355
                t = arg+*arg-1;
×
3356
                if ( *t < 0 ) { i = ((-*t)-1)/2; size = -i; }
×
3357
                else          { i = (  *t -1)/2; size =  i; }
×
3358
                t = arg+ARGHEAD+1;
×
3359
                NCOPY(scrat,t,i);
×
3360
        }
3361
        return(size);
60✔
3362
}
3363

3364
/*
3365
                 #] PutArgInScratch : 
3366
                 #[ ReadRange :
3367

3368
                Comes in at the bracket and leaves at the = sign
3369
                Ranges can be:
3370
                        #1,#2  with # numbers. If the second is smaller than the
3371
                                        first we work it backwards.
3372
                        first,#2 or #2,first
3373
                        #1,last  or last,#1
3374
                        first,last or last,first
3375
                First is represented by 1. Last is represented by MAXPOSITIVE4.
3376

3377
                par = 0: we need the = after.
3378
                par = 1: we need a , or '\0' after.
3379
                par = 2: we need a :
3380
*/
3381

3382
UBYTE *ReadRange(UBYTE *s, WORD *out, int par)
144✔
3383
{
3384
        UBYTE *in = s, *ss, c;
144✔
3385
        LONG x1, x2;
144✔
3386

3387
        SKIPBRA3(in)
1,134✔
3388
        if ( par == 0 && in[1] != '=' ) {
144✔
3389
                MesPrint("&A range in this type of transform statement should be followed by an = sign");
×
3390
                return(0);
×
3391
        }
3392
        else if ( par == 1 && in[1] != ',' && in[1] != '\0' ) {
144✔
3393
                MesPrint("&A range in this type of transform statement should be followed by a comma or end-of-statement");
×
3394
                return(0);
×
3395
        }
3396
        else if ( par == 2 && in[1] != ':' ) {
144✔
3397
                MesPrint("&A range in this type of transform statement should be followed by a :");
×
3398
                return(0);
×
3399
        }
3400
        s++;
144✔
3401
        if ( FG.cTable[*s] == 0 ) {
144✔
3402
                ss = s; while ( FG.cTable[*s] == 0 ) s++;
×
3403
                c = *s; *s = 0;
×
3404
                if ( StrICmp(ss,(UBYTE *)"first") == 0 ) {
×
3405
                        *s = c;
×
3406
                        x1 = 1;
×
3407
                }
3408
                else if ( StrICmp(ss,(UBYTE *)"last") == 0 ) {
×
3409
                        *s = c;
×
3410
                        if ( c == '-' ) {
×
3411
                                s++;
×
3412
                                if ( *s == '$' ) {
×
3413
                                        s++; ss = s;
×
3414
                                        while ( FG.cTable[*s] == 0 || FG.cTable[*s] == 1 ) s++;
×
3415
                                        c = *s; *s = 0;
×
3416
                                        if ( ( x1 = GetDollar(ss) ) < 0 ) goto Error;
×
3417
                                        *s = c;
×
3418
                                        x1 += MAXPOSITIVE2;
×
3419
                                }
3420
                                else {
3421
                                        x1 = 0;
3422
                                        while ( *s >= '0' && *s <= '9' ) {
×
3423
                                                x1 = 10*x1 + *s++ - '0';
×
3424
                                                if ( x1 >= MAXPOSITIVE4 ) {
×
3425
                                                        MesPrint("&Fixed range indicator bigger than %l",(LONG)MAXPOSITIVE4);
×
3426
                                                        return(0);
×
3427
                                                }
3428
                                        }
3429
                                }
3430
                                x1 += MAXPOSITIVE4;
×
3431
                        }
3432
                        else x1 = MAXPOSITIVE4;
3433
                }
3434
                else {
3435
                        MesPrint("&Illegal keyword inside range specification");
×
3436
                        return(0);
×
3437
                }
3438
        }
3439
        else if ( FG.cTable[*s] == 1 ) {
144✔
3440
                x1 = 0;
3441
                while ( *s >= '0' && *s <= '9' ) {
192✔
3442
                        x1 = x1*10 + *s++ - '0';
96✔
3443
                        if ( x1 >= MAXPOSITIVE4 ) {
96✔
3444
                                MesPrint("&Fixed range indicator bigger than %l",(LONG)MAXPOSITIVE4);
×
3445
                                return(0);
×
3446
                        }
3447
                }
3448
        }
3449
        else if ( *s == '$' ) {
48✔
3450
                s++; ss = s;
48✔
3451
                while ( FG.cTable[*s] == 0 || FG.cTable[*s] == 1 ) s++;
144✔
3452
                c = *s; *s = 0;
48✔
3453
                if ( ( x1 = GetDollar(ss) ) < 0 ) goto Error;
48✔
3454
                *s = c;
48✔
3455
                x1 += MAXPOSITIVE2;
48✔
3456
        }
3457
        else {
3458
                MesPrint("&Illegal character in range specification");
×
3459
                return(0);
×
3460
        }
3461
        if ( *s != ',' ) {
144✔
3462
                MesPrint("&A range is two indicators, separated by a comma or blank");
×
3463
                return(0);
×
3464
        }
3465
        s++;
144✔
3466
        if ( FG.cTable[*s] == 0 ) {
144✔
3467
                ss = s; while ( FG.cTable[*s] == 0 ) s++;
450✔
3468
                c = *s; *s = 0;
90✔
3469
                if ( StrICmp(ss,(UBYTE *)"first") == 0 ) {
90✔
3470
                        *s = c;
×
3471
                        x2 = 1;
×
3472
                }
3473
                else if ( StrICmp(ss,(UBYTE *)"last") == 0 ) {
90✔
3474
                        *s = c;
90✔
3475
                        if ( c == '-' ) {
90✔
3476
                                s++;
48✔
3477
                                if ( *s == '$' ) {
48✔
3478
                                        s++; ss = s;
24✔
3479
                                        while ( FG.cTable[*s] == 0 || FG.cTable[*s] == 1 ) s++;
72✔
3480
                                        c = *s; *s = 0;
24✔
3481
                                        if ( ( x2 = GetDollar(ss) ) < 0 ) goto Error;
24✔
3482
                                        *s = c;
24✔
3483
                                        x2 += MAXPOSITIVE2;
24✔
3484
                                }
3485
                                else {
3486
                                        x2 = 0;
3487
                                        while ( *s >= '0' && *s <= '9' ) {
48✔
3488
                                                x2 = 10*x2 + *s++ - '0';
24✔
3489
                                                if ( x2 >= MAXPOSITIVE4 ) {
24✔
3490
                                                        MesPrint("&Fixed range indicator bigger than %l",(LONG)MAXPOSITIVE4);
×
3491
                                                        return(0);
×
3492
                                                }
3493
                                        }
3494
                                }
3495
                                x2 += MAXPOSITIVE4;
48✔
3496
                        }
3497
                        else x2 = MAXPOSITIVE4;
3498
                }
3499
                else {
3500
                        MesPrint("&Illegal keyword inside range specification");
×
3501
                        return(0);
×
3502
                }
3503
        }
3504
        else if ( FG.cTable[*s] == 1 ) {
54✔
3505
                x2 = 0;
3506
                while ( *s >= '0' && *s <= '9' ) {
60✔
3507
                        x2 = x2*10 + *s++ - '0';
30✔
3508
                        if ( x2 >= MAXPOSITIVE4 ) {
30✔
3509
                                MesPrint("&Fixed range indicator bigger than %l",(LONG)MAXPOSITIVE4);
×
3510
                                return(0);
×
3511
                        }
3512
                }
3513
        }
3514
        else if ( *s == '$' ) {
24✔
3515
                s++; ss = s;
24✔
3516
                while ( FG.cTable[*s] == 0 || FG.cTable[*s] == 1 ) s++;
72✔
3517
                c = *s; *s = 0;
24✔
3518
                if ( ( x2 = GetDollar(ss) ) < 0 ) goto Error;
24✔
3519
                *s = c;
24✔
3520
                x2 += MAXPOSITIVE2;
24✔
3521
        }
3522
        else {
3523
                MesPrint("&Illegal character in range specification");
×
3524
                return(0);
×
3525
        }
3526
        if ( s < in ) {
144✔
3527
                MesPrint("&A range is two indicators, separated by a comma or blank between parentheses");
×
3528
                return(0);
×
3529
        }
3530
        out[0] = x1; out[1] = x2;
144✔
3531
        return(in+1);
144✔
3532
Error:
×
3533
        MesPrint("&Undefined variable $%s in range",ss);
×
3534
        return(0);
×
3535
}
3536

3537
/*
3538
                 #] ReadRange : 
3539
                 #[ FindRange :
3540
*/
3541

3542
int FindRange(PHEAD WORD *args, WORD *arg1, WORD *arg2, WORD totarg)
195✔
3543
{
3544
        WORD n[2], fromlast, i;
195✔
3545
        for ( i = 0; i < 2; i++ ) {
585✔
3546
                n[i] = args[i+1];
390✔
3547
                fromlast = 0;
390✔
3548
                if ( n[i] >= MAXPOSITIVE2 ) { /* This is a dollar variable */
390✔
3549
                        n[i] -= MAXPOSITIVE2;
96✔
3550
                        if ( n[i] >= MAXPOSITIVE4 ) {
96✔
3551
                                fromlast = 1;
24✔
3552
                                n[i] -= MAXPOSITIVE4; /* Now we have the number of the dollar variable   */
24✔
3553
                        }
3554
                        n[i] = DolToNumber(BHEAD n[i]);
96✔
3555
                        if ( AN.ErrorInDollar ) goto Error;
96✔
3556
                        if ( fromlast ) n[i] = totarg-n[i];
96✔
3557
                }
3558
                else if ( n[i] >= MAXPOSITIVE4 ) { n[i] = totarg-(n[i]-MAXPOSITIVE4); }
294✔
3559
                if ( n[i] <= 0 ) goto Error;
390✔
3560
        }
3561
        *arg1 = n[0];
195✔
3562
        *arg2 = n[1];
195✔
3563
        return(0);
195✔
3564
Error:
×
3565
        MLOCK(ErrorMessageLock);
×
3566
        MesPrint("Illegal $ value in range while executing transform statement.");
×
3567
        MUNLOCK(ErrorMessageLock);
×
3568
        return(-1);
×
3569
}
3570

3571
/*
3572
                 #] FindRange : 
3573
         #] Transform :
3574
*/
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc