FORM  4.1
comexpr.c
Go to the documentation of this file.
1 
8 /* #[ License : */
9 /*
10  * Copyright (C) 1984-2013 J.A.M. Vermaseren
11  * When using this file you are requested to refer to the publication
12  * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
13  * This is considered a matter of courtesy as the development was paid
14  * for by FOM the Dutch physics granting agency and we would like to
15  * be able to track its scientific use to convince FOM of its value
16  * for the community.
17  *
18  * This file is part of FORM.
19  *
20  * FORM is free software: you can redistribute it and/or modify it under the
21  * terms of the GNU General Public License as published by the Free Software
22  * Foundation, either version 3 of the License, or (at your option) any later
23  * version.
24  *
25  * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
26  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
27  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
28  * details.
29  *
30  * You should have received a copy of the GNU General Public License along
31  * with FORM. If not, see <http://www.gnu.org/licenses/>.
32  */
33 /* #] License : */
34 
35 /*
36  #[ Includes : compi2.c
37 
38  File contains most of what has to do with compiling expressions.
39  Main supporting file: token.c
40 */
41 
42 #include "form3.h"
43 
44 static struct id_options {
45  UBYTE *name;
46  int code;
47  int dummy;
48 } IdOptions[] = {
49  {(UBYTE *)"multi", SUBMULTI ,0}
50  ,{(UBYTE *)"many", SUBMANY ,0}
51  ,{(UBYTE *)"only", SUBONLY ,0}
52  ,{(UBYTE *)"once", SUBONCE ,0}
53  ,{(UBYTE *)"ifmatch", SUBAFTER ,0}
54  ,{(UBYTE *)"ifnomatch", SUBAFTERNOT ,0}
55  ,{(UBYTE *)"ifnotmatch", SUBAFTERNOT ,0}
56  ,{(UBYTE *)"disorder", SUBDISORDER ,0}
57  ,{(UBYTE *)"select", SUBSELECT ,0}
58 };
59 
60 /*
61  #] Includes :
62  #[ CoLocal :
63 */
64 
65 int CoLocal(UBYTE *inp) { return(DoExpr(inp,LOCALEXPRESSION,0)); }
66 
67 /*
68  #] CoLocal :
69  #[ CoGlobal :
70 */
71 
72 int CoGlobal(UBYTE *inp) { return(DoExpr(inp,GLOBALEXPRESSION,0)); }
73 
74 /*
75  #] CoGlobal :
76  #[ CoLocalFactorized :
77 */
78 
79 int CoLocalFactorized(UBYTE *inp) { return(DoExpr(inp,LOCALEXPRESSION,1)); }
80 
81 /*
82  #] CoLocalFactorized :
83  #[ CoGlobalFactorized :
84 */
85 
86 int CoGlobalFactorized(UBYTE *inp) { return(DoExpr(inp,GLOBALEXPRESSION,1)); }
87 
88 /*
89  #] CoGlobalFactorized :
90  #[ DoExpr:
91 
92 
93 */
94 
95 int DoExpr(UBYTE *inp, int type, int par)
96 {
97  GETIDENTITY
98  int error = 0;
99  UBYTE *p, *q, c;
100  WORD *w, i, j = 0, c1, c2, *OldWork = AT.WorkPointer, osize;
101  WORD jold = 0;
102  POSITION pos;
103  while ( *inp == ',' ) inp++;
104  if ( par ) AC.ToBeInFactors = 1;
105  else AC.ToBeInFactors = 0;
106  p = inp;
107  while ( *p && *p != '=' ) {
108  if ( *p == '(' ) SKIPBRA4(p)
109  else if ( *p == '{' ) SKIPBRA5(p)
110  else if ( *p == '[' ) SKIPBRA1(p)
111  else p++;
112  }
113  if ( *p ) { /* Variety with the = sign */
114  if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
115  MesPrint("&Illegal name for expression");
116  error = 1;
117  if ( q[-1] == '_' ) {
118  while ( FG.cTable[*q] < 2 || *q == '_' ) q++;
119  }
120  }
121  else {
122  c = *q; *q = 0;
123  if ( GetVar(inp,&c1,&c2,ALLVARIABLES,NOAUTO) != NAMENOTFOUND ) {
124  if ( c1 == CEXPRESSION ) {
125  if ( Expressions[c2].status == STOREDEXPRESSION ) {
126  MesPrint("&Illegal attempt to overwrite a stored expression");
127  error = 1;
128  }
129  else {
130  HighWarning("Expression is replaced by new definition");
131  if ( AO.OptimizeResult.nameofexpr != NULL &&
132  StrCmp(inp,AO.OptimizeResult.nameofexpr) == 0 ) {
133  ClearOptimize();
134  }
135  if ( Expressions[c2].status != DROPPEDEXPRESSION ) {
136  w = &(Expressions[c2].status);
137  if ( *w == LOCALEXPRESSION || *w == SKIPLEXPRESSION )
138  *w = DROPLEXPRESSION;
139  else if ( *w == GLOBALEXPRESSION || *w == SKIPGEXPRESSION )
140  *w = DROPGEXPRESSION;
141  }
142  AC.TransEname = Expressions[c2].name;
143  j = EntVar(CEXPRESSION,0,type,0,0,0);
144  Expressions[j].node = Expressions[c2].node;
145  Expressions[c2].replace = j;
146  }
147  }
148  else {
149  MesPrint("&name of expression is also name of a variable");
150  error = 1;
151  j = EntVar(CEXPRESSION,inp,type,0,0,0);
152  }
153  jold = c2;
154  }
155  else {
156 /*
157  Here we have to worry about reuse of the expression in the
158  same module. That will need AS.Oldvflags but that may not
159  be defined or have the proper value.
160 */
161  j = EntVar(CEXPRESSION,inp,type,0,0,0);
162  jold = j;
163  }
164  *q = c;
165  OldWork = w = AT.WorkPointer;
166  *w++ = TYPEEXPRESSION;
167  *w++ = 3+SUBEXPSIZE;
168  *w++ = j;
169  AC.ProtoType = w;
170  AR.CurExpr = j; /* Block expression j */
171  *w++ = SUBEXPRESSION;
172  *w++ = SUBEXPSIZE;
173  *w++ = j;
174  *w++ = 1;
175  *w++ = AC.cbufnum;
176  FILLSUB(w)
177 
178  if ( c == '(' ) {
179  while ( *q == ',' || *q == '(' ) {
180  inp = q+1;
181  if ( ( q = SkipAName(inp) ) == 0 ) {
182  MesPrint("&Illegal name for expression argument");
183  error = 1;
184  q = p - 1;
185  break;
186  }
187  c = *q; *q = 0;
188  if ( GetVar(inp,&c1,&c2,ALLVARIABLES,WITHAUTO) < 0 ) c1 = -1;
189  switch ( c1 ) {
190  case CSYMBOL :
191  *w++ = SYMTOSYM; *w++ = 4; *w++ = c2; *w++ = 0;
192  break;
193  case CINDEX :
194  *w++ = INDTOIND; *w++ = 4;
195  *w++ = c2 + AM.OffsetIndex; *w++ = 0;
196  break;
197  case CVECTOR :
198  *w++ = VECTOVEC; *w++ = 4;
199  *w++ = c2 + AM.OffsetVector; *w++ = 0;
200  break;
201  case CFUNCTION :
202  *w++ = FUNTOFUN; *w++ = 4; *w++ = c2 + FUNCTION; *w++ = 0;
203  break;
204  default :
205  MesPrint("&Illegal expression parameter: %s",inp);
206  error = 1;
207  break;
208  }
209  *q = c;
210  }
211  if ( *q != ')' || q+1 != p ) {
212  MesPrint("&Illegal use of arguments for expression");
213  error = 1;
214  }
215  AC.ProtoType[1] = w - AC.ProtoType;
216  }
217  *w++ = 1;
218  *w++ = 1;
219  *w++ = 3;
220  *w++ = 0;
221  SeekScratch(AR.outfile,&pos);
222  Expressions[j].counter = 1;
223  Expressions[j].onfile = pos;
224  Expressions[j].whichbuffer = 0;
225 #ifdef PARALLELCODE
226  Expressions[j].partodo = AC.inparallelflag;
227 #endif
228  OldWork[2] = w - OldWork - 3;
229  AT.WorkPointer = w;
230 /*
231  Writing the expression prototype to disk and to the compiler
232  buffer is done only after the RHS has been compiled because
233  we don't know the number of the main level RHS yet.
234 */
235  }
236  inp = p+1;
237  ClearWildcardNames();
238  osize = AC.ProtoType[1]; AC.ProtoType[1] = SUBEXPSIZE;
239  if ( ( i = CompileAlgebra(inp,RHSIDE,AC.ProtoType) ) < 0 ) {
240  AC.ProtoType[1] = osize;
241  error = 1;
242  }
243  else if ( error == 0 ) {
244  AC.ProtoType[1] = osize;
245  AC.ProtoType[2] = i;
246 /* AR.outfile->POfill = AR.outfile->POfull; */
247  if ( PutOut(BHEAD OldWork+2,&pos,AR.outfile,0) < 0 ) {
248  MesPrint("&Cannot create expression");
249  error = -1;
250  }
251  else {
252  OldWork[2] = 4+SUBEXPSIZE;
253  OldWork[4] = SUBEXPSIZE;
254  OldWork[5] = i;
255  OldWork[SUBEXPSIZE+3] = 1;
256  OldWork[SUBEXPSIZE+4] = 1;
257  OldWork[SUBEXPSIZE+5] = 3;
258  OldWork[SUBEXPSIZE+6] = 0;
259  if ( PutOut(BHEAD OldWork+2,&pos,AR.outfile,0) < 0
260  || FlushOut(&pos,AR.outfile,0) ) {
261  MesPrint("&Cannot create expression");
262  error = -1;
263  }
264 /*
265  The next statement repairs a bug that occurs with
266  L F2 = .....
267  #$d = F1[x];
268  in which the POfull was less than POfill and the setting
269  of the Scratch file in store.c goes wrong.
270  15-oct-2006 JV
271 */
272  AR.outfile->POfull = AR.outfile->POfill;
273  }
274  OldWork[2] = j;
275  AddNtoL(OldWork[1],OldWork);
276  AT.WorkPointer = OldWork;
277  if ( AC.dumnumflag ) Add2Com(TYPEDETCURDUM)
278  }
279  PutInVflags(jold);
280  AC.ToBeInFactors = 0;
281  }
282  else { /* Variety in which expressions change property */
283 /*
284  This code got a major revision because it didn't
285  take hidden expressions into account. (1-jun-2010 JV)
286 */
287  do {
288  if ( ( q = SkipAName(inp) ) == 0 ) {
289  MesPrint("&Illegal name(s) for expression(s)");
290  return(1);
291  }
292  c = *q; *q = 0;
293  if ( GetName(AC.exprnames,inp,&c2,NOAUTO) == NAMENOTFOUND ) {
294  MesPrint("&%s is not a valid expression",inp);
295  error = 1;
296  }
297  else {
298  w = &(Expressions[c2].status);
299  if ( type == LOCALEXPRESSION ) {
300  switch ( *w ) {
301  case GLOBALEXPRESSION:
302  *w = LOCALEXPRESSION;
303  break;
304  case SKIPGEXPRESSION:
305  *w = SKIPLEXPRESSION;
306  break;
307  case DROPGEXPRESSION:
308  *w = DROPLEXPRESSION;
309  break;
310  case HIDDENGEXPRESSION:
311  *w = HIDDENLEXPRESSION;
312  break;
313  case HIDEGEXPRESSION:
314  *w = HIDELEXPRESSION;
315  break;
316  case UNHIDEGEXPRESSION:
317  *w = UNHIDELEXPRESSION;
318  break;
319  case INTOHIDEGEXPRESSION:
320  *w = INTOHIDELEXPRESSION;
321  break;
322  }
323  }
324  else if ( type == GLOBALEXPRESSION ) {
325  switch ( *w ) {
326  case LOCALEXPRESSION:
327  *w = GLOBALEXPRESSION;
328  break;
329  case SKIPLEXPRESSION:
330  *w = SKIPGEXPRESSION;
331  break;
332  case DROPLEXPRESSION:
333  *w = DROPGEXPRESSION;
334  break;
335  case HIDDENLEXPRESSION:
336  *w = HIDDENGEXPRESSION;
337  break;
338  case HIDELEXPRESSION:
339  *w = HIDEGEXPRESSION;
340  break;
341  case UNHIDELEXPRESSION:
342  *w = UNHIDEGEXPRESSION;
343  break;
344  case INTOHIDELEXPRESSION:
345  *w = INTOHIDEGEXPRESSION;
346  break;
347  }
348  }
349 /*
350  old code
351  if ( type != LOCALEXPRESSION || *w != STOREDEXPRESSION )
352  *w = type;
353 */
354  }
355  *q = c; inp = q+1;
356  } while ( c == ',' );
357  if ( c ) {
358  MesPrint("&Illegal object in local or global redefinition");
359  error = 1;
360  }
361  }
362  return(error);
363 }
364 
365 /*
366  #] DoExpr:
367  #[ CoIdOld :
368 */
369 
370 int CoIdOld(UBYTE *inp)
371 {
372  AC.idoption = 0;
373  return(CoIdExpression(inp,TYPEIDOLD));
374 }
375 
376 /*
377  #] CoIdOld :
378  #[ CoId :
379 */
380 
381 int CoId(UBYTE *inp)
382 {
383  AC.idoption = 0;
384  return(CoIdExpression(inp,TYPEIDNEW));
385 }
386 
387 /*
388  #] CoId :
389  #[ CoIdNew :
390 */
391 
392 int CoIdNew(UBYTE *inp)
393 {
394  AC.idoption = 0;
395  return(CoIdExpression(inp,TYPEIDNEW));
396 }
397 
398 /*
399  #] CoIdNew :
400  #[ CoDisorder :
401 */
402 
403 int CoDisorder(UBYTE *inp)
404 {
405  AC.idoption = SUBDISORDER;
406  return(CoIdExpression(inp,TYPEIDNEW));
407 }
408 
409 /*
410  #] CoDisorder :
411  #[ CoMany :
412 */
413 
414 int CoMany(UBYTE *inp)
415 {
416  AC.idoption = SUBMANY;
417  return(CoIdExpression(inp,TYPEIDNEW));
418 }
419 
420 /*
421  #] CoMany :
422  #[ CoMulti :
423 */
424 
425 int CoMulti(UBYTE *inp)
426 {
427  AC.idoption = SUBMULTI;
428  return(CoIdExpression(inp,TYPEIDNEW));
429 }
430 
431 /*
432  #] CoMulti :
433  #[ CoIfMatch :
434 */
435 
436 int CoIfMatch(UBYTE *inp)
437 {
438  AC.idoption = SUBAFTER;
439  return(CoIdExpression(inp,TYPEIDNEW));
440 }
441 
442 /*
443  #] CoIfMatch :
444  #[ CoIfNoMatch :
445 */
446 
447 int CoIfNoMatch(UBYTE *inp)
448 {
449  AC.idoption = SUBAFTERNOT;
450  return(CoIdExpression(inp,TYPEIDNEW));
451 }
452 
453 /*
454  #] CoIfNoMatch :
455  #[ CoOnce :
456 */
457 
458 int CoOnce(UBYTE *inp)
459 {
460  AC.idoption = SUBONCE;
461  return(CoIdExpression(inp,TYPEIDNEW));
462 }
463 
464 /*
465  #] CoOnce :
466  #[ CoOnly :
467 */
468 
469 int CoOnly(UBYTE *inp)
470 {
471  AC.idoption = SUBONLY;
472  return(CoIdExpression(inp,TYPEIDNEW));
473 }
474 
475 /*
476  #] CoOnly :
477  #[ CoSelect :
478 */
479 
480 int CoSelect(UBYTE *inp)
481 {
482  AC.idoption = SUBSELECT;
483  return(CoIdExpression(inp,TYPEIDNEW));
484 }
485 
486 /*
487  #] CoSelect :
488  #[ CoIdExpression :
489 
490  First finish dealing with secondary keywords
491 */
492 
493 int CoIdExpression(UBYTE *inp, int type)
494 {
495  GETIDENTITY
496  int i, j, idhead, error = 0, MinusSign = 0, opt, retcode;
497  WORD *w, *s, *m, *mm, *ww, *FirstWork, *OldWork, c1, numsets = 0,
498  oldnumrhs, *ow, oldEside;
499  UBYTE *p, *pp, c;
500  CBUF *C = cbuf+AC.cbufnum;
501  LONG oldcpointer;
502  FirstWork = OldWork = AT.WorkPointer;
503 /*
504  Don't forget to change in StudyPattern if we change/add_to the
505  following setup.
506  if ( type == TYPEIF ) idhead = IDHEAD-1;
507  else
508 */
509  idhead = IDHEAD;
510  AR.CurExpr = -1;
511  w = AT.WorkPointer;
512  *w++ = type;
513  *w++ = idhead + SUBEXPSIZE;
514  w++;
515  if ( idhead >= IDHEAD ) *w++ = -1;
516 #if IDHEAD > 4
517  for ( i = 4; i < idhead; i++ ) *w++ = 0;
518 #endif
519  while ( *inp == ',' ) inp++;
520  p = inp;
521  if ( AC.idoption == SUBSELECT ) {
522  p--;
523  goto findsets;
524  }
525  else if ( ( AC.idoption == SUBAFTER ) || ( AC.idoption == SUBAFTERNOT ) ) {
526  while ( *p && *p != '=' && *p != ',' ) {
527  if ( *p == '(' ) SKIPBRA4(p)
528  else if ( *p == '{' ) SKIPBRA5(p)
529  else if ( *p == '[' ) SKIPBRA1(p)
530  else p++;
531  }
532  if ( *p == '=' || *inp != '-' || inp[1] != '>' ) {
533  MesPrint("&Illegal use if if[no]match in id statement");
534  error = 1; goto AllDone;
535  }
536  if ( *p == 0 ) {
537  MesPrint("&id-statement without = sign");
538  error = 1; goto AllDone;
539  }
540  inp += 2; pp = inp;
541  goto readlabel;
542  }
543  for(;;) {
544  while ( *p && *p != '=' && *p != ',' ) {
545  if ( *p == '(' ) SKIPBRA4(p)
546  else if ( *p == '{' ) SKIPBRA5(p)
547  else if ( *p == '[' ) SKIPBRA1(p)
548  else p++;
549  }
550  if ( *p == '=' ) break;
551  if ( *p == 0 ) {
552  MesPrint("&id-statement without = sign");
553  error = 1; goto AllDone;
554  }
555 /*
556  We have either a secondary option or a syntax error
557 */
558  pp = inp;
559  while ( FG.cTable[*pp] == 0 ) pp++;
560  c = *pp; *pp = 0;
561  i = sizeof(IdOptions)/sizeof(struct id_options);
562  while ( --i >= 0 ) {
563  if ( StrICmp(inp,IdOptions[i].name) == 0 ) break;
564  }
565  if ( i < 0 ) {
566  MesPrint("&Illegal option %s in id-statement",inp);
567  *pp = c; error = 1; p++; inp = p; continue;
568  }
569  opt = IdOptions[i].code;
570  *pp = c;
571  inp = pp+1;
572  switch ( opt ) {
573  case SUBDISORDER:
574  if ( pp != p ) goto IllField;
575  AC.idoption |= SUBDISORDER;
576  p++; inp = p;
577  break;
578  case SUBSELECT:
579  if ( p != pp ) goto IllField;
580  if ( ( AC.idoption & SUBMASK ) != 0 ) {
581  if ( AC.idoption == SUBMULTI && type == TYPEIF ) {}
582  else {
583  MesPrint("&Conflicting options in id-statement");
584  error = 1;
585  }
586  }
587 findsets:;
588 /*
589  Now we read the sets
590 */
591  numsets = 0;
592  for(;;) {
593  inp = ++p;
594  while ( *p && *p != '=' && *p != ',' ) {
595  if ( *p == '(' ) SKIPBRA4(p)
596  else if ( *p == '{' ) SKIPBRA5(p)
597  else if ( *p == '[' ) SKIPBRA1(p)
598  else p++;
599  }
600  if ( *p == '=' ) break;
601  if ( *p == 0 ) {
602  MesPrint("&id-statement without = sign");
603  error = 1; goto AllDone;
604  }
605 /*
606  We have a set at inp.
607 */
608  if ( *inp == '{' ) {
609  if ( p[-1] != '}' ) {
610  c = *p; *p = 0;
611  MesPrint("&Illegal temporary set: %s",inp);
612  error = 1; *p = c;
613  }
614  else {
615  inp++;
616  c = p[-1]; p[-1] = 0;
617  c1 = DoTempSet(inp,p-1);
618  *w++ = c1;
619  p[-1] = c;
620  numsets++;
621  if ( w[-1] < 0 ) error = 1;
622  }
623  }
624  else {
625  c = *p; *p = 0;
626  if ( GetName(AC.varnames,inp,&c1,NOAUTO) != CSET ) {
627  MesPrint("&%s is not a set",inp);
628  error = 1;
629  }
630  else {
631  if ( c1 < AM.NumFixedSets ) {
632  MesPrint("&Built in sets are not allowed in the select option");
633  error = 1;
634  }
635  else if ( Sets[c1].type == CRANGE ) {
636  MesPrint("&Ranged sets are not allowed in the select option");
637  error = 1;
638  }
639  numsets++;
640  *w++ = c1;
641  }
642  *p = c;
643  }
644  }
645 /*
646  Now exchange the positions a bit.
647  Regular stuff at OldWork, numsets sets at FirstWork[idhead]
648 */
649  OldWork = w;
650  for ( i = 0; i < idhead; i++ ) *w++ = FirstWork[i];
651  AC.idoption = SUBSELECT;
652  break;
653  case SUBAFTER:
654  case SUBAFTERNOT:
655  if ( type == TYPEIF ) {
656  MesPrint("&The if[no]match->label option is not allowed in an if statement");
657  error = 1; goto AllDone;
658  }
659  if ( pp[0] != '-' || pp[1] != '>' ) goto IllField;
660  pp += 2; /* points now at the label */
661  inp = pp;
662  AC.idoption |= opt;
663 readlabel:
664  while ( FG.cTable[*pp] <= 1 ) pp++;
665  if ( pp != p ) {
666  c = *p; *p = 0;
667  MesPrint("&Illegal label %s in if[no]match option of id-statement",inp);
668  *p = c; error = 1; inp = p+1; continue;
669  }
670  c = *p; *p = 0;
671  OldWork[3] = GetLabel(inp);
672  *p++ = c; inp = p;
673  break;
674  default:
675  if ( pp != p ) {
676 IllField: c = *p; *p = 0;
677  MesPrint("&Illegal optionfield %s in id-statement",inp);
678  *p = c; error = 1; inp = p+1; continue;
679  }
680  i = AC.idoption & SUBMASK;
681  if ( i && i != opt ) {
682  MesPrint("&Conflicting options in id-statement");
683  error = 1; continue;
684  }
685  else AC.idoption |= opt;
686  while ( *p == ',' ) p++;
687  inp = p;
688  break;
689  }
690  }
691  if ( ( AC.idoption & SUBMASK ) == 0 ) AC.idoption |= SUBMULTI;
692  OldWork[2] = AC.idoption;
693 /*
694  Now we have a field till the = sign
695  Now the subexpression prototype
696 */
697  AC.ProtoType = w;
698  *w++ = SUBEXPRESSION;
699  *w++ = SUBEXPSIZE;
700  *w++ = C->numrhs+1;
701  *w++ = 1;
702  *w++ = AC.cbufnum;
703  FILLSUB(w)
704  AC.WildC = w;
705  AC.NwildC = 0;
706  AT.WorkPointer = s = w + 4*AM.MaxWildcards + 8;
707 /*
708  Now read the LHS
709 */
710  oldcpointer = AddLHS(AC.cbufnum) - C->Buffer;
711 
712  *p = 0;
713  oldnumrhs = C->numrhs;
714  if ( ( retcode = CompileAlgebra(inp,LHSIDE,AC.ProtoType) ) < 0 ) { error = 1; }
715  else AC.ProtoType[2] = retcode;
716  *p = '='; inp = p+1;
717  AT.WorkPointer = s;
718  if ( AC.NwildC && SortWild(w,AC.NwildC) ) error = 1;
719 
720  /* Make the LHS pointers ready */
721 
722  OldWork[1] = AC.WildC-OldWork;
723  OldWork[idhead+1] = OldWork[1] - idhead;
724  w = AC.WildC;
725  AT.WorkPointer = w;
726  s = C->rhs[C->numrhs];
727 /*
728  Now check whether wildcards get converted to dollars (for PARALLEL)
729 */
730  {
731  WORD *tw, *twstop;
732  tw = AC.ProtoType; twstop = tw + tw[1]; tw += SUBEXPSIZE;
733  while ( tw < twstop ) {
734  if ( *tw == LOADDOLLAR ) {
735  AddPotModdollar(tw[2]);
736  }
737  tw += tw[1];
738  }
739  }
740 /*
741  We have the expression in the compiler buffers.
742  The main level is at lhs[numlhs]
743  The partial lhs (including ProtoType) is in OldWork (in WorkSpace)
744  We need to load the result at w after the prototype
745  Because these sort routines don't use the WorkSpace
746  there should not be a conflict
747 */
748  if ( !error && *s == 0 ) {
749 IllLeft:MesPrint("&Illegal LHS");
750  AC.lhdollarflag = 0;
751  return(1);
752  }
753  if ( !error && *(s+*s) != 0 ) {
754  MesPrint("&LHS should be one term only");
755  return(1);
756  }
757  if ( error == 0 ) {
758  if ( NewSort(BHEAD0) || NewSort(BHEAD0) ) {
759  if ( !error ) error = 1;
760  return(error);
761  }
762  AN.RepPoint = AT.RepCount + 1;
763  ow = (WORD *)(((UBYTE *)(AT.WorkPointer)) + AM.MaxTer);
764  mm = s; ww = ow; i = *mm;
765  while ( --i >= 0 ) *ww++ = *mm++; AT.WorkPointer = ww;
766  AC.lhdollarflag = 0; oldEside = AR.Eside; AR.Eside = LHSIDE;
767  AR.Cnumlhs = C->numlhs;
768  if ( Generator(BHEAD ow,C->numlhs) ) {
769  AR.Eside = oldEside;
770  LowerSortLevel(); LowerSortLevel(); goto IllLeft;
771  }
772  AR.Eside = oldEside;
773  AT.WorkPointer = w;
774  if ( EndSort(BHEAD w,0) < 0 ) { LowerSortLevel(); goto IllLeft; }
775  if ( *w == 0 || *(w+*w) != 0 ) {
776  MesPrint("&LHS must be one term");
777  AC.lhdollarflag = 0;
778  return(1);
779  }
780  LowerSortLevel();
781  if ( AC.lhdollarflag ) MarkDirty(w,DIRTYFLAG);
782  }
783  AT.WorkPointer = w + *w;
784  AC.DumNum = 0;
785 /*
786  Everything is now after OldWork. We can pop the compilerbuffer.
787  Next test for illegal things like a coefficient
788  At this point we have:
789  w = the term of the LHS
790 */
791  C->Pointer = C->Buffer + oldcpointer;
792  C->numrhs = oldnumrhs;
793  C->numlhs--;
794 
795  m = w + *w - 3;
796  if ( !error ) {
797  if ( m[2] != 3 || m[1] != 1 || *m != 1 ) {
798  if ( *m == 1 && m[1] == 1 && m[2] == -3 ) {
799  MinusSign = 1;
800  }
801  else {
802  MesPrint("&Coefficient in LHS");
803  error = 1;
804  AC.DumNum = 0;
805  *w -= ABS(m[2])-3;
806  }
807  }
808  if ( *w == 7 && w[1] == INDEX && w[3] < 0 ) {
809  if ( ( AC.idoption & SUBMASK ) != 0 && ( AC.idoption & SUBMASK ) !=
810  SUBMULTI ) {
811  MesPrint("&Illegal option for substitution of a vector");
812  error = 1;
813  }
814  AC.DumNum = AM.IndDum;
815  OldWork[2] = ( OldWork[2] - ( OldWork[2] & SUBMASK ) ) | SUBALL;
816  c1 = w[3];
817  /* We overwrite the LHS */
818  *w++ = INDTOIND;
819  *w++ = 4;
820  *w++ = AC.DumNum + WILDOFFSET;
821  *w++ = 0;
822  w[0] = 5;
823  w[1] = VECTOR;
824  w[2] = 4;
825  w[3] = c1;
826  w[4] = AC.DumNum + WILDOFFSET;
827  OldWork[idhead+1] = w - OldWork - idhead;
828  }
829  else {
830  AC.DumNum = 0;
831  *w -= 3;
832  i = OldWork[2] & SUBMASK;
833  m = w + *w;
834  if ( i == 0 || i == SUBMULTI ) {
835  s = w+1;
836  while ( s < m ) {
837  if ( *s == SYMBOL ) {
838  j = s[1]/2; s += 2;
839  while ( --j >= 0 ) {
840  if ( ABS(s[1]) > 2*MAXPOWER ) {
841  OldWork[2] = ( OldWork[2] - i ) | SUBONCE;
842  break;
843  }
844  s += 2;
845  }
846  if ( j >= 0 ) break;
847  }
848  else if ( *s == DOTPRODUCT ) {
849  j = s[1]/3; s += 2;
850  while ( --j >= 0 ) {
851  if ( ABS(s[2]) > 2*MAXPOWER ) {
852  OldWork[2] = ( OldWork[2] - i ) | SUBONCE;
853  break;
854  }
855  else if ( s[1] >= -(2*WILDOFFSET) || s[0] >= -(2*WILDOFFSET) ) {
856  OldWork[2] = ( OldWork[2] - i ) | SUBMANY;
857  i = SUBMANY;
858  }
859  s += 3;
860  }
861  if ( j >= 0 ) break;
862  }
863  else {
864  OldWork[2] = ( OldWork[2] - i ) | SUBMANY;
865  break;
866  }
867  }
868  }
869  if ( ( OldWork[2] & SUBMASK ) == 0 ) OldWork[2] |= SUBMULTI;
870  }
871  if ( ( OldWork[2] & SUBMASK ) == SUBSELECT ) {
872 /*
873  Paste the SETSET information after the pattern.
874  Important note: We will still get function information for the
875  smart patternmatching after it. To distinguish them we need to have
876  that SETSET != m*n+1 in which m is the number of words per function
877  and n the number of functions. Currently (29-may-1997) m = 4.
878 */
879  *m++ = SETSET;
880  *m++ = numsets+2;
881  s = FirstWork + idhead;
882  while ( --numsets >= 0 ) *m++ = *s++;
883  }
884  else {
885  m = w + *w;
886  }
887  }
888 /*
889  We keep the whole thing in OldWork for the moment.
890  We still have to add the number of the RHS expression.
891  There is also some opportunity now to be smart about the pattern.
892  This is needed for complicated wildcarding with symmetric functions.
893  We do this in a special routine during compile time to make sure
894  that we loose as little time as possible (during running) if there
895  is no need to be smart.
896 */
897  *m++ = 0;
898  OldWork[1] = m - OldWork;
899  AC.ProtoType = OldWork+idhead;
900  if ( !error ) {
901  if ( StudyPattern(OldWork) ) error = 1;
902  }
903  AT.WorkPointer = OldWork + OldWork[1];
904  OldWork[4] = AC.lhdollarflag;
905  AC.lhdollarflag = 0;
906 /*
907  Now the right hand side.
908 */
909  if ( type != TYPEIF ) {
910  if ( ( retcode = CompileAlgebra(inp,RHSIDE,AC.ProtoType) ) < 0 ) error = 1;
911  else {
912  AC.ProtoType[2] = retcode;
913  AC.DumNum = 0;
914  if ( MinusSign ) { /* Flip the sign of the RHS */
915  w = C->rhs[retcode];
916  while ( *w ) { w += *w; w[-1] = -w[-1]; }
917  }
918  if ( AC.dumnumflag ) Add2Com(TYPEDETCURDUM)
919  }
920  }
921 /*
922  Actual adding happens only now after numrhs insertion
923 */
924  /* if ( !error ) */ { AddNtoL(OldWork[1],OldWork); }
925 AllDone:
926  AC.lhdollarflag = 0;
927  AT.WorkPointer = FirstWork;
928  return(error);
929 }
930 
931 /*
932  #] CoIdExpression :
933  #[ CoMultiply :
934 */
935 
936 static WORD mularray[13] = { TYPEMULT, SUBEXPSIZE+3, 0, SUBEXPRESSION,
937  SUBEXPSIZE, 0, 1, 0, 0, 0, 0, 0, 0 };
938 
939 int CoMultiply(UBYTE *inp)
940 {
941  UBYTE *p;
942  int error = 0, RetCode;
943  mularray[2] = 0; /* right multiply is default */
944  while ( *inp == ',' ) inp++;
945 /* if ( inp[-1] == '-' || inp[-1] == '+' ) inp--; */
946  p = SkipField(inp,0);
947  if ( *p ) {
948  *p = 0;
949  if ( StrICont(inp,(UBYTE *)"left") == 0 ) mularray[2] = 1;
950  else if ( StrICont(inp,(UBYTE *)"right") == 0 ) mularray[2] = 0;
951  else {
952  MesPrint("&Illegal option in multiply statement or ; forgotten.");
953  return(1);
954  }
955  *p = ',';
956  inp = p + 1;
957  }
958  while ( *inp == ',' ) inp++;
959  AC.ProtoType = mularray+3;
960  mularray[7] = AC.cbufnum;
961  if ( ( RetCode = CompileAlgebra(inp,RHSIDE,AC.ProtoType) ) < 0 ) error = 1;
962  else {
963  mularray[5] = RetCode;
964  AddNtoL(SUBEXPSIZE+3,mularray);
965  if ( AC.dumnumflag ) Add2Com(TYPEDETCURDUM)
966  }
967  return(error);
968 }
969 
970 /*
971  #] CoMultiply :
972  #[ CoFill :
973 
974  Special additions for tablebase-like tables added 12-aug-2002
975 */
976 
977 int CoFill(UBYTE *inp)
978 {
979  GETIDENTITY
980  WORD error = 0, x, funnum, type, *oldwp = AT.WorkPointer;
981  int i, oldcbufnum = AC.cbufnum, nofill = 0, numover, redef = 0;
982  WORD *w, *wold, *Tprototype;
983  UBYTE *p = inp, c, *inp1;
984  TABLES T = 0, oldT;
985  LONG newreservation, sum = 0;
986  UBYTE *p1, *p2, *p3, *p4, *fake = 0;
987  int tablestub = 0;
988  if ( AC.exprfillwarning == 1 ) AC.exprfillwarning = 0;
989 /*
990  Read the name of the function and test that it is in the table.
991 */
992  p1 = inp;
993  if ( ( p = SkipAName(inp) ) == 0 ) return(1);
994  p2 = p;
995  c = *p; *p = 0;
996  if ( ( GetVar(inp,&type,&funnum,CFUNCTION,WITHAUTO) == NAMENOTFOUND )
997  || ( T = functions[funnum].tabl ) == 0 || c != '(' ) {
998  MesPrint("&%s should be a table with argument(s)",inp);
999  *p = c; return(1);
1000  }
1001  oldT = T;
1002  *p++ = c;
1003  for ( sum = 0, i = 0, w = oldwp; i < T->numind; i++ ) {
1004  ParseSignedNumber(x,p);
1005  if ( FG.cTable[p[-1]] != 1 || ( *p != ',' && *p != ')' ) ) {
1006  MesPrint("&Table arguments in fill statement should be numbers");
1007  return(1);
1008  }
1009  if ( T->sparse ) *w++ = x;
1010  else if ( x < T->mm[i].mini || x > T->mm[i].maxi ) {
1011  MesPrint("&Value %d for argument %d of table out of bounds",x,i+1);
1012  error = 1; nofill = 1;
1013  }
1014  else sum += ( x - T->mm[i].mini ) * T->mm[i].size;
1015  if ( *p == ')' ) break;
1016  p++;
1017  }
1018  p3 = p;
1019  if ( *p != ')' || i < ( T->numind - 1 ) ) {
1020  MesPrint("&Incorrect number of table arguments in fill statement. Should be %d"
1021  ,T->numind);
1022  error = 1; nofill = 1;
1023  }
1024  AT.WorkPointer = w;
1025  if ( T->sparse == 0 ) sum *= TABLEEXTENSION;
1026 andagain:;
1027  AC.cbufnum = T->bufnum;
1028  if ( T->sparse ) {
1029  i = FindTableTree(T,oldwp,1);
1030  if ( i >= 0 ) {
1031  sum = i + T->numind;
1032  if ( tablestub == 0 && ( ( T->sparse & 2 ) == 2 ) && ( T->mode != 0 )
1033  && ( AC.vetotablebasefill == 0 ) ) {
1034 /*
1035  This redefinition does not need a new stub
1036 */
1037  functions[funnum].tabl = T = T->spare;
1038  tablestub = 1;
1039  goto andagain;
1040  }
1041  redef = 1;
1042  goto redef;
1043  }
1044  if ( T->totind >= T->reserved ) {
1045  if ( T->reserved == 0 ) newreservation = 20;
1046  else newreservation = T->reserved;
1047 /*
1048  while ( T->totind >= newreservation && newreservation <
1049  MAXTABLECOMBUF*(T->numind+TABLEEXTENSION) )
1050  if ( newreservation > MAXTABLECOMBUF*T->numind ) newreservation =
1051  5*(T->numind+TABLEEXTENSION);
1052 */
1053  while ( T->totind >= newreservation && newreservation < MAXTABLECOMBUF )
1054  newreservation = 2*newreservation;
1055  if ( newreservation > MAXTABLECOMBUF ) newreservation = MAXTABLECOMBUF;
1056  if ( T->totind >= newreservation ) {
1057  MesPrint("@More than %ld elements in sparse table",MAXTABLECOMBUF);
1058  AC.cbufnum = oldcbufnum;
1059  Terminate(-1);
1060  }
1061  wold = (WORD *)Malloc1(newreservation*sizeof(WORD)*
1062  (T->numind+TABLEEXTENSION),"tablepointers");
1063  for ( i = T->reserved*(T->numind+TABLEEXTENSION)-1; i >= 0; i-- )
1064  wold[i] = T->tablepointers[i];
1065  if ( T->tablepointers ) M_free(T->tablepointers,"tablepointers");
1066  T->tablepointers = wold;
1067  T->reserved = newreservation;
1068  }
1069  w = oldwp;
1070  for ( sum = T->totind*(T->numind+TABLEEXTENSION), i = 0; i < T->numind; i++ ) {
1071  T->tablepointers[sum++] = *w++;
1072  }
1073  InsTableTree(T,T->tablepointers+sum-T->numind);
1074 #if TABLEEXTENSION == 2
1075  T->tablepointers[sum+TABLEEXTENSION-1] = -1; /* New element! */
1076 #else
1077  T->tablepointers[sum+1] = T->bufnum;
1078  T->tablepointers[sum+2] = -1;
1079  T->tablepointers[sum+3] = -1;
1080  T->tablepointers[sum+4] = 0;
1081  T->tablepointers[sum+5] = 0;
1082 #endif
1083  }
1084  else {
1085  if ( !nofill && T->tablepointers[sum] >= 0 ) {
1086 redef:;
1087  if ( AC.vetofilling ) nofill = 1;
1088  else {
1089  Warning("Table element was already defined. New definition will be used");
1090  }
1091  }
1092 #if TABLEEXTENSION == 2
1093  T->tablepointers[sum+TABLEEXTENSION-1] = -1; /* New element! */
1094 #else
1095  T->tablepointers[sum+1] = T->bufnum;
1096  T->tablepointers[sum+2] = -1;
1097  T->tablepointers[sum+3] = -1;
1098  T->tablepointers[sum+4] = 0;
1099  T->tablepointers[sum+5] = 0;
1100 #endif
1101  }
1102  p++; if ( *p != '=' ) {
1103  MesPrint("&Fill statement misses = sign after the table element");
1104  AC.cbufnum = oldcbufnum;
1105  AT.WorkPointer = oldwp;
1106  functions[funnum].tabl = oldT;
1107  return(1);
1108  }
1109  if ( tablestub == 0 && T->mode == 1 && AC.vetotablebasefill == 0 ) {
1110 /*
1111  Here we construct a righthandside from the indices and the wildcards
1112 */
1113  int numfake;
1114  tablestub = 1;
1115  p4 = T->argtail;
1116  while ( *p4 ) p4++;
1117  numfake = (p4-T->argtail)+(p3-p1)+10;
1118 
1119  fake = (UBYTE *)Malloc1(numfake*sizeof(UBYTE),"Fill fake rhs");
1120  p = fake;
1121  *p++ = 't'; *p++ = 'b'; *p++ = 'l'; *p++ = '_'; *p++ = '(';
1122  p4 = p1; while ( p4 < p2 ) *p++ = *p4++; *p++ = ',';
1123  p4 = p2+1; while ( p4 < p3 ) *p++ = *p4++;
1124  if ( T->argtail ) {
1125  p4 = T->argtail + 1;
1126  while ( FG.cTable[*p4] == 1 ) p4++;
1127  while ( *p4 ) {
1128  if ( *p4 == '?' && p[-1] != ',' ) {
1129  p4++;
1130  if ( FG.cTable[*p4] == 0 || *p4 == '$' || *p4 == '[' ) {
1131  p4 = SkipAName(p4);
1132  if ( *p4 == '[' ) {
1133  SKIPBRA1(p4);
1134  }
1135  }
1136  else if ( *p4 == '{' ) {
1137  SKIPBRA2(p4);
1138  }
1139  else if ( *p4 ) { *p++ = *p4++; continue; }
1140  }
1141  else *p++ = *p4++;
1142  }
1143  }
1144  *p++ = ')';
1145  *p = 0;
1146  inp1 = fake;
1147 /* AT.WorkPointer += T->numind; */
1148  }
1149  else
1150  inp1 = ++p; c = 0;
1151 /*
1152  Now we have the indices and p points to the rhs.
1153 */
1154  numover = 0;
1155  AC.tablefilling = funnum;
1156  while ( *inp1 ) {
1157  p = SkipField(inp1,0);
1158  c = *p; *p = 0;
1159 #ifdef WITHPTHREADS
1160  Tprototype = T->prototype[0];
1161 #else
1162  Tprototype = T->prototype;
1163 #endif
1164  if ( ( i = CompileAlgebra(inp1,RHSIDE,Tprototype) ) < 0 ) { error = 1; i = 0; }
1165  if ( !nofill ) {
1166  T->tablepointers[sum] = i;
1167  T->tablepointers[sum+1] = T->bufnum;
1168  }
1169  AC.DumNum = 0;
1170  *p = c;
1171  if ( T->sparse || c == 0 ) break;
1172  inp1 = ++p;
1173 #if ( TABLEEXTENSION == 2 )
1174  sum++;
1175 #else
1176  sum += 2;
1177 #endif
1178  if ( !nofill && T->tablepointers[sum] >= 0 ) numover++;
1179 #if ( TABLEEXTENSION == 2 )
1180  sum++;
1181 #else
1182  sum += TABLEEXTENSION-2;
1183 #endif
1184  }
1185  if ( AC.exprfillwarning == 1 ) {
1186  AC.exprfillwarning = 2;
1187  Warning("Use of expressions and/or $variables in Fill statements is potentially very dangerous.");
1188  }
1189  AC.tablefilling = 0;
1190  if ( T->sparse && c != 0 ) {
1191  MesPrint("&In sparse tables one can fill only one element at a time");
1192  error = 1;
1193  }
1194  else if ( numover ) {
1195  if ( numover == 1 )
1196  Warning("one element was overwritten. New definition will be used");
1197  else if ( AC.WarnFlag )
1198  MesPrint("&Warning: %d elements were overwritten. New definitions will be used",numover);
1199  }
1200  if ( T->sparse ) {
1201  if ( redef == 0 ) T->totind++;
1202  }
1203  else T->defined++;
1204 /*
1205  NumSets = AC.SetList.numtemp;
1206  NumSetElements = AC.SetElementList.numtemp;
1207 */
1208  if ( fake ) {
1209  M_free(fake,"Fill fake rhs");
1210  fake = 0;
1211  functions[funnum].tabl = T = T->spare;
1212  p = p3;
1213  goto andagain;
1214  }
1215  AC.cbufnum = oldcbufnum;
1216  AC.SymChangeFlag = 1;
1217  AT.WorkPointer = oldwp;
1218  functions[funnum].tabl = oldT;
1219  return(error);
1220 }
1221 
1222 /*
1223  #] CoFill :
1224  #[ CoFillExpression :
1225 
1226  Syntax: FillExpression table = expression(x1,...,xn);
1227  The arguments should have been bracketed. Each corresponds to one
1228  of the dimensions of the table. Then the bracket with x1^2*x3^4
1229  will fill the (2,0,4) element of the table (if n=3 of course).
1230  Brackets that don't fit will be skipped. It just gives a warning.
1231 
1232  New option (13-jul-2005)
1233  Syntax: FillExpression table = expression(f);
1234  The table indices are arguments of the function f which should
1235  have been bracketed before.
1236 */
1237 
1238 int CoFillExpression(UBYTE *inp)
1239 {
1240  GETIDENTITY
1241  UBYTE *p, c;
1242  WORD type, funnum, expnum, symnum, numsym = 0, *oldwork = AT.WorkPointer;
1243  WORD *brackets, *term, brasize, *b, *m, *w, *pw, *tstop, zero = 0;
1244  WORD oldcbuf = AC.cbufnum, curelement = 0;
1245  int weneedit, i, j, numzero, pow;
1246  TABLES T = 0;
1247  LONG newreservation, numcommu, sum;
1248  POSITION oldposition;
1249  FILEHANDLE *fi;
1250  CBUF *C;
1251  WORD numdummies;
1252 
1253  AN.IndDum = AM.IndDum;
1254  if ( ( p = SkipAName(inp) ) == 0 ) return(1);
1255  c = *p; *p = 0;
1256  if ( ( GetVar(inp,&type,&funnum,CFUNCTION,NOAUTO) == NAMENOTFOUND )
1257  || ( T = functions[funnum].tabl ) == 0 ) {
1258  MesPrint("&%s should be a previously declared table",inp);
1259  *p = c; return(1);
1260  }
1261  *p++ = c;
1262  if ( T->spare ) T = T->spare;
1263  C = cbuf + T->bufnum;
1264  if ( c != '=' ) {
1265  MesPrint("&No = sign in FillExpression statement");
1266  return(1);
1267  }
1268  inp = p;
1269  if ( ( p = SkipAName(inp) ) == 0 ) return(1);
1270  c = *p; *p = 0;
1271  if ( ( type = GetName(AC.exprnames,inp,&expnum,NOAUTO) ) == NAMENOTFOUND
1272  || c != '(' || (
1273  Expressions[expnum].status != LOCALEXPRESSION &&
1274  Expressions[expnum].status != SKIPLEXPRESSION &&
1275  Expressions[expnum].status != DROPLEXPRESSION &&
1276  Expressions[expnum].status != GLOBALEXPRESSION &&
1277  Expressions[expnum].status != SKIPGEXPRESSION &&
1278  Expressions[expnum].status != DROPGEXPRESSION ) ) {
1279  MesPrint("&%s should be an active expression with arguments",inp);
1280  *p = c; return(1);
1281  }
1282  if ( Expressions[expnum].inmem ) {
1283  MesPrint("&%s cannot be used in a FillExpression statement in the same %n\
1284  module that it has been redefined",inp);
1285  *p = c; return(1);
1286  }
1287  *p++ = c;
1288  while ( *p ) {
1289  inp = p;
1290  if ( ( p = SkipAName(inp) ) == 0 ) return(1);
1291  c = *p; *p = 0;
1292 
1293  if ( GetVar(inp,&type,&symnum,-1,NOAUTO) == NAMENOTFOUND ) {
1294  MesPrint("&%s should be a previously declared symbol or function",inp);
1295  *p = c; return(1);
1296  }
1297  else if ( type == CSYMBOL ) {
1298  *p++ = c;
1299  *AT.WorkPointer++ = symnum;
1300  numsym++;
1301  }
1302  else if ( type == CFUNCTION ) {
1303  numsym = -1;
1304  *p++ = c;
1305  if ( c != ')' ) {
1306  MesPrint("&Argument should be a single function or a list of symbols");
1307  return(1);
1308  }
1309  symnum += FUNCTION;
1310  *AT.WorkPointer++ = symnum;
1311  }
1312  else {
1313  MesPrint("&%s should be a previously declared symbol or function",inp);
1314  *p = c; return(1);
1315  }
1316 /*
1317  if ( GetVar(inp,&type,&symnum,CSYMBOL,NOAUTO) == NAMENOTFOUND ) {
1318  if ( numsym > 0 ) {
1319  MesPrint("&%s should be a previously declared symbol",inp);
1320  *p = c; return(1);
1321  }
1322  else {
1323  if ( GetVar(inp,&type,&symnum,CFUNCTION,NOAUTO) == NAMENOTFOUND ) {
1324  MesPrint("&%s should be a previously declared symbol or function",inp);
1325  *p = c; return(1);
1326  }
1327  numsym = -1;
1328  *p++ = c;
1329  if ( c != ')' ) {
1330  MesPrint("&Argument should be a single function or a list of symbols");
1331  *p = c; return(1);
1332  }
1333  symnum += FUNCTION;
1334  *AT.WorkPointer++ = symnum;
1335  break;
1336  }
1337  }
1338  *p++ = c;
1339  *AT.WorkPointer++ = symnum;
1340  numsym++;
1341 */
1342  if ( c == ')' ) break;
1343  if ( c != ',' ) {
1344  MesPrint("&Illegal separator in FillExpression statement");
1345  goto noway;
1346  }
1347  }
1348  if ( *p ) {
1349  MesPrint("&Illegal end of FillExpression statement");
1350  goto noway;
1351  }
1352 /*
1353  We have the number of the table in funnum.
1354  The number of the expression in expnum, the table struct in T
1355  and either the numbers of the symbols in oldwork (there are numsym of them)
1356  or the number of the function in oldwork (just one and numsym = -1).
1357  We don't sort them!!!!
1358 */
1359  if ( ( numsym > 0 ) && ( T->numind != numsym ) ) {
1360  MesPrint("&This table needs %d symbols for its array indices");
1361  goto noway;
1362  }
1363  EXCHINOUT
1364  fi = AR.infile;
1365  if ( fi->handle >= 0 ) {
1366  PUTZERO(oldposition);
1367  SeekFile(fi->handle,&oldposition,SEEK_CUR);
1368  SetScratch(fi,&(Expressions[expnum].onfile));
1369 /* SeekFile(fi->handle,&(Expressions[expnum].onfile),SEEK_SET); */
1370  if ( ISNEGPOS(Expressions[expnum].onfile) ) {
1371  MesPrint("&File error in FillExpression");
1372  BACKINOUT
1373  goto noway;
1374  }
1375  }
1376  else {
1377 /*
1378  Note: Because everything fits inside memory we never get problems
1379  with excessive file sizes.
1380 */
1381  SETBASEPOSITION(oldposition,(UBYTE *)(fi->POfill)-(UBYTE *)(fi->PObuffer));
1382  fi->POfill = (WORD *)((UBYTE *)(fi->PObuffer) + BASEPOSITION(Expressions[expnum].onfile));
1383  }
1384  pw = AT.WorkPointer;
1385  if ( numsym < 0 ) { brackets = pw + 1; }
1386  else { brackets = pw + numsym; }
1387  brasize = -1; weneedit = 0; /* stands for we need it */
1388  term = (WORD *)(((UBYTE *)(brackets)) + AM.MaxTer);
1389  AT.WorkPointer = (WORD *)(((UBYTE *)(term)) + AM.MaxTer);
1390  AC.cbufnum = T->bufnum;
1391  AC.tablefilling = funnum;
1392  if ( GetTerm(BHEAD term) > 0 ) { /* Skip prototype */
1393  while ( GetTerm(BHEAD term) > 0 ) {
1394  GETSTOP(term,tstop);
1395  w = m = term + 1;
1396  while ( m < tstop && *m != HAAKJE ) m += m[1];
1397  if ( *m != HAAKJE ) {
1398  MesPrint("&Illegal attempt to put an expression without brackets in a table");
1399  BACKINOUT
1400  goto noway;
1401  }
1402  if ( brasize == m - w ) {
1403  b = brackets;
1404  while ( *b == *w && w < m ) { b++; w++; }
1405  if ( w == m ) { /* Same as current bracket. Copy. */
1406  if ( weneedit ) {
1407  m += m[1] - 1;
1408  *m = *term - (m-term);
1409  AddNtoC(AC.cbufnum,*m,m);
1410  numdummies = DetCurDum(BHEAD term) - AM.IndDum;
1411  if ( numdummies > T->numdummies ) T->numdummies = numdummies;
1412  }
1413  continue; /* Next term */
1414  }
1415  }
1416  if ( weneedit ) {
1417  AddNtoC(AC.cbufnum,1,&zero); /* Terminate old bracket */
1418  numcommu = numcommute(C->rhs[curelement],&(C->NumTerms[curelement]));
1419  C->CanCommu[curelement] = numcommu;
1420  }
1421  b = brackets; w = term + 1;
1422  if ( numsym < 0 ) pw = oldwork + 1;
1423  else pw = oldwork + numsym;
1424  while ( w < m ) *b++ = *w++;
1425  brasize = b - brackets;
1426 /*
1427  Now compute the element. See whether we need it
1428 */
1429  if ( numsym < 0 ) {
1430  WORD *bb;
1431  if ( *brackets != symnum || brasize != brackets[1] ) {
1432  weneedit = 0; continue; /* Cannot work! */
1433  }
1434 /*
1435  Now count the number of arguments and whether they are numbers
1436 */
1437  b = brackets + FUNHEAD;
1438  bb = brackets+brackets[1];
1439  i = 0;
1440  while ( b < bb ) {
1441  if ( *b != -SNUMBER ) break;
1442  i++;
1443  b += 2;
1444  }
1445  if ( b < bb || i != T->numind ) {
1446  weneedit = 0; continue; /* Cannot work! */
1447  }
1448  }
1449  else if ( brasize > 0 && ( *brackets != SYMBOL
1450  || brackets[1] < brasize || (brackets[1]-2) > numsym*2 ) ) {
1451  weneedit = 0; continue; /* Cannot work! */
1452  }
1453  numzero = 0; sum = 0;
1454  if ( numsym > 0 ) {
1455  for ( i = 0; i < numsym; i++ ) {
1456  if ( brasize > 0 ) {
1457  b = brackets + 2; j = brackets[1]-2;
1458  while ( j > 0 ) {
1459  if ( *b == oldwork[i] ) break;
1460  j -= 2; b += 2;
1461  }
1462  if ( j <= 0 ) { /* it was not there */
1463  numzero++; pow = 0;
1464  if ( 2*numzero+brackets[1]-2 > numsym*2 ) {
1465  weneedit = 0; goto nextterm;
1466  }
1467  }
1468  else pow = b[1];
1469  }
1470  else pow = 0;
1471  if ( T->sparse ) *pw++ = pow;
1472  else if ( pow < T->mm[i].mini || pow > T->mm[i].maxi ) {
1473  weneedit = 0; goto nextterm;
1474  }
1475  else sum += ( pow - T->mm[i].mini ) * T->mm[i].size;
1476  }
1477  }
1478  else {
1479  b = brackets + FUNHEAD;
1480  sum = 0;
1481  for ( i = 0; i < T->numind; i++ ) {
1482  pow = b[1];
1483  b += 2;
1484  if ( T->sparse ) { *pw++ = pow; }
1485  else if ( pow < T->mm[i].mini || pow > T->mm[i].maxi ) {
1486  weneedit = 0; goto nextterm;
1487  }
1488  else sum += ( pow - T->mm[i].mini ) * T->mm[i].size;
1489  }
1490  }
1491  weneedit = 1;
1492  if ( T->sparse ) {
1493  if ( numsym < 0 ) pw = oldwork + 1;
1494  else pw = oldwork + T->numind;
1495  i = FindTableTree(T,pw,1);
1496  if ( i >= 0 ) {
1497  sum = i+T->numind;
1498 /*
1499 Wrong!!!! C->rhs[T->tablepointers[sum]] = C->Pointer;
1500 */
1501  C->Pointer--; /* Back up over the zero */
1502  goto newentry;
1503  }
1504  if ( T->totind >= T->reserved ) {
1505  if ( T->reserved == 0 ) newreservation = 20;
1506  else newreservation = T->reserved;
1507 /*
1508  while ( T->totind >= newreservation && newreservation <
1509  MAXTABLECOMBUF*(T->numind+TABLEEXTENSION) )
1510  newreservation = 2*newreservation;
1511  if ( newreservation > MAXTABLECOMBUF*T->numind ) newreservation =
1512  MAXTABLECOMBUF*(T->numind+TABLEEXTENSION);
1513 */
1514 /*---Copied from Fill---------------------------*/
1515  while ( T->totind >= newreservation && newreservation < MAXTABLECOMBUF )
1516  newreservation = 2*newreservation;
1517  if ( newreservation > MAXTABLECOMBUF ) newreservation = MAXTABLECOMBUF;
1518  if ( T->totind >= newreservation ) {
1519  MesPrint("@More than %ld elements in sparse table",MAXTABLECOMBUF);
1520  AC.cbufnum = oldcbuf;
1521  AT.WorkPointer = oldwork;
1522  Terminate(-1);
1523  }
1524 /*---Copied from Fill---------------------------*/
1525  if ( T->totind >= newreservation ) {
1526  MesPrint("@More than %ld elements in sparse table",MAXTABLECOMBUF);
1527  AC.cbufnum = oldcbuf;
1528  AT.WorkPointer = oldwork;
1529  Terminate(-1);
1530  }
1531  w = (WORD *)Malloc1(newreservation*sizeof(WORD)*
1532  (T->numind+TABLEEXTENSION),"tablepointers");
1533  for ( i = T->reserved*(T->numind+TABLEEXTENSION)-1; i >= 0; i-- )
1534  w[i] = T->tablepointers[i];
1535  if ( T->tablepointers ) M_free(T->tablepointers,"tablepointers");
1536  T->tablepointers = w;
1537  T->reserved = newreservation;
1538  }
1539  if ( numsym < 0 ) pw = oldwork + 1;
1540  else pw = oldwork + numsym;
1541  for ( sum = T->totind*(T->numind+TABLEEXTENSION), i = 0; i < T->numind; i++ ) {
1542  T->tablepointers[sum++] = *pw++;
1543  }
1544  InsTableTree(T,T->tablepointers+sum-T->numind);
1545  (T->totind)++;
1546  }
1547 #if ( TABLEEXTENSION != 2 )
1548  else {
1549  sum *= TABLEEXTENSION;
1550  }
1551 #endif
1552 /*
1553  Start a new entry. Copy the element.
1554 */
1555  AddRHS(T->bufnum,0);
1556  T->tablepointers[sum] = C->numrhs;
1557 #if ( TABLEEXTENSION == 2 )
1558  T->tablepointers[sum+TABLEEXTENSION-1] = -1;
1559 #else
1560  T->tablepointers[sum+1] = T->bufnum;
1561  T->tablepointers[sum+2] = -1;
1562  T->tablepointers[sum+3] = -1;
1563  T->tablepointers[sum+4] = 0;
1564  T->tablepointers[sum+5] = 0;
1565 #endif
1566 newentry: if ( *m == HAAKJE ) { m += m[1] - 1; }
1567  else m--;
1568  *m = *term - (m-term);
1569  AddNtoC(AC.cbufnum,*m,m);
1570  curelement = T->tablepointers[sum];
1571 nextterm:;
1572  }
1573  if ( weneedit ) {
1574  AddNtoC(AC.cbufnum,1,&zero); /* Terminate old bracket */
1575  numcommu = numcommute(C->rhs[curelement],&(C->NumTerms[curelement]));
1576  C->CanCommu[curelement] = numcommu;
1577  }
1578  }
1579  if ( fi->handle >= 0 ) {
1580  SetScratch(fi,&(oldposition));
1581  }
1582  else {
1583  fi->POfill = (WORD *)((UBYTE *)(fi->PObuffer) + BASEPOSITION(oldposition));
1584  }
1585  BACKINOUT
1586  AC.cbufnum = oldcbuf;
1587  AC.tablefilling = 0;
1588  AT.WorkPointer = oldwork;
1589  return(0);
1590 noway:
1591  BACKINOUT
1592  AC.cbufnum = oldcbuf;
1593  AC.tablefilling = 0;
1594  AT.WorkPointer = oldwork;
1595  return(1);
1596 }
1597 
1598 /*
1599  #] CoFillExpression :
1600  #[ CoPrintTable :
1601 
1602  Syntax
1603  PrintTable [+f] [+s] tablename [>[>] file];
1604  All defined elements are written with individual Fill statements.
1605  If a file is specified, the result is written to file only.
1606  The flags of the print statement apply as much as possible.
1607  We make use of the regular write routines.
1608 */
1609 
1610 int CoPrintTable(UBYTE *inp)
1611 {
1612  GETIDENTITY
1613  int fflag = 0, sflag = 0, addflag = 0, error = 0, sum, i, j;
1614  UBYTE *filename, *p, c, buffer[100], *s, *oldoutputline = AO.OutputLine;
1615  WORD type, funnum, *expr, *m, num;
1616  TABLES T = 0;
1617  WORD oldSkip = AO.OutSkip, oldMode = AC.OutputMode, oldHandle = AC.LogHandle;
1618  WORD oldType = AO.PrintType, *oldwork = AT.WorkPointer;
1619  UBYTE *oldFill = AO.OutFill, *oldLine = AO.OutputLine;
1620 #ifdef WITHMPI
1621  if ( PF.me != MASTER ) return 0;
1622 #endif
1623 /*
1624  First the flags
1625 */
1626  while ( *inp == '+' ) {
1627  inp++;
1628  if ( *inp == 'f' || *inp == 'F' ) { fflag = 1; inp++; }
1629  else if ( *inp == 's' || *inp == 'S' ) { sflag = PRINTONETERM; inp++; }
1630  else {
1631  MesPrint("&Illegal + option in PrintTable statement");
1632  error = 1; inp++;
1633  }
1634  while ( *inp != ',' && *inp && *inp != '+' ) {
1635  if ( !error ) {
1636  if ( *inp ) {
1637  MesPrint("&Illegal + option in PrintTable statement");
1638  inp++;
1639  }
1640  else {
1641  MesPrint("&Unfinished PrintTable statement");
1642  return(1);
1643  }
1644  error = 1;
1645  }
1646  inp++;
1647  }
1648  if ( *inp == ',' ) inp++;
1649  }
1650 /*
1651  Now the name of the table
1652 */
1653  if ( ( p = SkipAName(inp) ) == 0 ) return(1);
1654  c = *p; *p = 0;
1655  if ( ( GetVar(inp,&type,&funnum,CFUNCTION,NOAUTO) == NAMENOTFOUND )
1656  || ( T = functions[funnum].tabl ) == 0 ) {
1657  MesPrint("&%s should be a previously declared table",inp);
1658  *p = c; return(1);
1659  }
1660  if ( T->spare && T->mode == 1 ) T = T->spare;
1661  *p++ = c;
1662 /*
1663  Check for a filename. Runs to the end of the statement.
1664 */
1665  filename = 0;
1666  if ( c == '>' ) {
1667  if ( *p == '>' ) { addflag = 1; p++; }
1668  filename = p;
1669  }
1670  else filename = 0;
1671 
1672  if ( filename ) {
1673  if ( addflag ) AC.LogHandle = OpenAddFile((char *)filename);
1674  else AC.LogHandle = CreateFile((char *)filename);
1675  if ( AC.LogHandle < 0 ) {
1676  MesPrint("&Cannot open file '%s' properly",filename);
1677  error = 1; goto finally;
1678  }
1679  AO.PrintType = PRINTLFILE;
1680  }
1681  else if ( fflag && AC.LogHandle >= 0 ) {
1682  AO.PrintType = PRINTLFILE;
1683  }
1684  AO.OutFill = AO.OutputLine = (UBYTE *)AT.WorkPointer;
1685  AT.WorkPointer += 2*AC.LineLength;
1686 
1687  AO.PrintType |= sflag;
1688  AC.OutputMode = 0;
1689  AO.IsBracket = 0;
1690  AO.OutSkip = 0;
1691  AR.DeferFlag = 0;
1692  AC.outsidefun = 1;
1693  if ( AC.LogHandle == oldHandle ) FiniLine();
1694  AO.OutputLine = AO.OutFill = (UBYTE *)Malloc1(AC.LineLength+20,"PrintTable");
1695  AO.OutStop = AO.OutFill + AC.LineLength;
1696  for ( i = 0; i < T->totind; i++ ) {
1697  if ( !T->sparse && T->tablepointers[i*TABLEEXTENSION] < 0 ) continue;
1698  TokenToLine((UBYTE *)"Fill ");
1699  TokenToLine((UBYTE *)(VARNAME(functions,funnum)));
1700  TokenToLine((UBYTE *)"(");
1701  AO.OutSkip = 3;
1702  if ( T->sparse ) {
1703  sum = i * ( T->numind + TABLEEXTENSION );
1704  for ( j = 0; j < T->numind; j++, sum++ ) {
1705  if ( j > 0 ) TokenToLine((UBYTE *)",");
1706  num = T->tablepointers[sum];
1707  s = buffer; s = NumCopy(num,s);
1708  TokenToLine(buffer);
1709  }
1710  expr = cbuf[T->bufnum].rhs[T->tablepointers[sum]];
1711  }
1712  else {
1713  for ( j = 0; j < T->numind; j++ ) {
1714  if ( j > 0 ) {
1715  TokenToLine((UBYTE *)",");
1716  num = T->mm[j].mini + ( i % T->mm[j-1].size ) / T->mm[j].size;
1717  }
1718  else {
1719  num = T->mm[j].mini + i / T->mm[j].size;
1720  }
1721  s = buffer; s = NumCopy(num,s);
1722  TokenToLine(buffer);
1723  }
1724  expr = cbuf[T->bufnum].rhs[T->tablepointers[TABLEEXTENSION*i]];
1725  }
1726  TOKENTOLINE(") =",")=");
1727  if ( sflag ) {
1728  FiniLine();
1729  if ( AC.OutputSpaces != NOSPACEFORMAT ) TokenToLine((UBYTE *)" ");
1730  }
1731  m = expr;
1732 /*
1733  WORD lbrac, first;
1734  lbrac = 0; first = 1;
1735  while ( *m ) {
1736  if ( WriteTerm(m,&lbrac,first,1,0) ) {
1737  MesPrint("Error while writing table");
1738  error = 1;
1739  goto finally;
1740  }
1741  first = 0;
1742  m += *m;
1743  }
1744  if ( first ) { TOKENTOLINE(" 0","0") }
1745  else if ( lbrac ) { TOKENTOLINE(" )",")") }
1746 */
1747  while ( *m ) m += *m;
1748  if ( m > expr ) {
1749  if ( WriteExpression(expr,(LONG)(m-expr)) ) { error = 1; goto finally; }
1750  AO.OutSkip = 0;
1751  }
1752  else {
1753  TokenToLine((UBYTE *)"0");
1754  }
1755  TokenToLine((UBYTE *)";");
1756  FiniLine();
1757  }
1758  M_free(AO.OutputLine,"PrintTable");
1759  AO.OutputLine = AO.OutFill = oldoutputline;
1760 /*
1761  Reset the file pointers and parameters if any. Close file if needed.
1762 */
1763 finally:
1764  AO.OutSkip = oldSkip;
1765  AC.OutputMode = oldMode;
1766  AC.LogHandle = oldHandle;
1767  AO.PrintType = oldType;
1768  AO.OutFill = oldFill;
1769  AO.OutputLine = oldLine;
1770  AT.WorkPointer = oldwork;
1771  AC.outsidefun = 0;
1772  return(error);
1773 }
1774 
1775 /*
1776  #] CoPrintTable :
1777  #[ CoAssign :
1778 
1779  This statement has an easy syntax:
1780  $name = expression
1781 */
1782 
1783 static WORD AssignLHS[14] = { TYPEASSIGN, 3+SUBEXPSIZE, 0,
1784  SUBEXPRESSION, SUBEXPSIZE, 0, 1, 0, 0,0,0,0,0 };
1785 
1786 int CoAssign(UBYTE *inp)
1787 {
1788  int error = 0, retcode;
1789  UBYTE *name, c;
1790  WORD number;
1791  if ( *inp != '$' ) {
1792 nolhs: MesPrint("&assign statement should have a dollar variable in the LHS");
1793  return(1);
1794  }
1795  inp++; name = inp;
1796  if ( FG.cTable[*inp] != 0 ) goto nolhs;
1797  while ( FG.cTable[*inp] < 2 ) inp++;
1798  if ( AP.PreAssignFlag == 2 ) {
1799  if ( *inp == '_' ) inp++;
1800  }
1801  if ( ( *inp == ',' && inp[1] != '=' ) && ( *inp != '=' ) ) {
1802  MesPrint("&assign statement should have only a dollar variable in the LHS");
1803  return(1);
1804  }
1805  c = *inp;
1806  *inp = 0;
1807  if ( GetName(AC.dollarnames,name,&number,NOAUTO) == NAMENOTFOUND ) {
1808  number = AddDollar(name,DOLUNDEFINED,0,0);
1809  }
1810  *inp = c;
1811  if ( c == ',' ) inp++;
1812  *inp++ = '=';
1813  if ( *inp == ',' ) inp++;
1814 /*
1815  Fake a Prototype and read the RHS
1816 */
1817  AssignLHS[7] = AC.cbufnum;
1818  retcode = CompileAlgebra(inp,RHSIDE,(AssignLHS+3));
1819  if ( retcode < 0 ) error = 1;
1820  AC.DumNum = 0;
1821 /*
1822  Now add the LHS
1823 */
1824  AssignLHS[2] = number;
1825  AssignLHS[5] = retcode;
1826  AddNtoL(AssignLHS[1],AssignLHS);
1827 /*
1828  Add to the list of potentially modified dollars (for PARALLEL)
1829 */
1830  AddPotModdollar(number);
1831  return(error);
1832 }
1833 
1834 /*
1835  #] CoAssign :
1836  #[ CoDeallocateTable :
1837 
1838  Syntax: DeallocateTable tablename(s);
1839  Should work only for sparse tables.
1840  Action: Cleans all definitions of elements of a table as if there have
1841  never been any fill statements.
1842 */
1843 
1844 int CoDeallocateTable(UBYTE *inp)
1845 {
1846  UBYTE *p, c;
1847  TABLES T = 0;
1848  WORD type, funnum, i;
1849  c = *inp;
1850  while ( c ) {
1851  while ( *inp == ',' ) inp++;
1852  if ( *inp == 0 ) break;
1853  if ( ( p = SkipAName(inp) ) == 0 ) return(1);
1854  c = *p; *p = 0;
1855  if ( ( GetVar(inp,&type,&funnum,CFUNCTION,NOAUTO) == NAMENOTFOUND )
1856  || ( T = functions[funnum].tabl ) == 0 ) {
1857  MesPrint("&%s should be a previously declared table",inp);
1858  *p = c; return(1);
1859  }
1860  if ( T->sparse == 0 ) {
1861  MesPrint("&%s should be a sparse table",inp);
1862  *p = c; return(1);
1863  }
1864  if ( T->tablepointers ) M_free(T->tablepointers,"tablepointers");
1865  ClearTableTree(T);
1866  for (i = 0; i < T->buffersfill; i++ ) { /* was <= */
1867  finishcbuf(T->buffers[i]);
1868  }
1869  T->bufnum = inicbufs();
1870  T->buffersfill = 0;
1871  T->buffers[T->buffersfill++] = T->bufnum;
1872  T->tablepointers = 0;
1873  T->boomlijst = 0;
1874  T->totind = 0;
1875  T->reserved = 0;
1876 
1877  if ( T->spare ) {
1878  TABLES TT = T->spare;
1879  if ( TT->tablepointers ) M_free(TT->tablepointers,"tablepointers");
1880  ClearTableTree(TT);
1881  for (i = 0; i < TT->buffersfill; i++ ) { /* was <= */
1882  finishcbuf(TT->buffers[i]);
1883  }
1884  TT->bufnum = inicbufs();
1885  TT->buffersfill = 0;
1886  TT->buffers[T->buffersfill++] = T->bufnum;
1887  TT->tablepointers = 0;
1888  TT->boomlijst = 0;
1889  TT->totind = 0;
1890  TT->reserved = 0;
1891  }
1892  *p++ = c;
1893  inp = p;
1894  }
1895  return(0);
1896 }
1897 
1898 /*
1899  #] CoDeallocateTable :
1900  #[ CoFactorCache :
1901 */
1911 /*
1912 int CoFactorCache(UBYTE *inp)
1913 {
1914  Code to be added in due time
1915  We need to read 'expression', get its terms through Generator and sort them.
1916  We store the result in the WorkSpace in argument notation.
1917  This will be argin.
1918  Then we do the same with the sequence of factors. They form argout.
1919  The whole is put in the buffer with the call
1920  InsertArg(BHEAD argin,argout,1)
1921  return(0);
1922 }
1923 */
1924 
1925 /*
1926  #] CoFactorCache :
1927 */
LONG * NumTerms
Definition: structs.h:915
void AddPotModdollar(WORD)
Definition: dollar.c:3771
WORD * buffers
Definition: structs.h:352
LONG reserved
Definition: structs.h:354
LONG totind
Definition: structs.h:353
WORD size
Definition: structs.h:297
Definition: structs.h:618
int sparse
Definition: structs.h:361
struct TaBlEs * spare
Definition: structs.h:351
WORD mode
Definition: structs.h:369
int numind
Definition: structs.h:358
WORD mini
Definition: structs.h:295
Definition: structs.h:908
WORD * Pointer
Definition: structs.h:911
WORD maxi
Definition: structs.h:296
WORD * tablepointers
Definition: structs.h:338
UBYTE * argtail
Definition: structs.h:349
WORD ** rhs
Definition: structs.h:913
WORD bufnum
Definition: structs.h:365
WORD buffersfill
Definition: structs.h:367
LONG defined
Definition: structs.h:355
MINMAX * mm
Definition: structs.h:346
VOID LowerSortLevel()
Definition: sort.c:4435
COMPTREE * boomlijst
Definition: structs.h:348
WORD * prototype
Definition: structs.h:343
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition: sort.c:1300
WORD * Buffer
Definition: structs.h:909
WORD NewSort(PHEAD0)
Definition: sort.c:553
WORD Generator(PHEAD WORD *, WORD)
Definition: proces.c:2865
WORD FlushOut(POSITION *, FILEHANDLE *, int)
Definition: sort.c:1621
LONG EndSort(PHEAD WORD *, int)
Definition: sort.c:632
LONG * CanCommu
Definition: structs.h:914