FORM v5.0.0-35-g6318119
tables.c
Go to the documentation of this file.
1
6/* #[ License : */
7/*
8 * Copyright (C) 1984-2026 J.A.M. Vermaseren
9 * When using this file you are requested to refer to the publication
10 * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
11 * This is considered a matter of courtesy as the development was paid
12 * for by FOM the Dutch physics granting agency and we would like to
13 * be able to track its scientific use to convince FOM of its value
14 * for the community.
15 *
16 * This file is part of FORM.
17 *
18 * FORM is free software: you can redistribute it and/or modify it under the
19 * terms of the GNU General Public License as published by the Free Software
20 * Foundation, either version 3 of the License, or (at your option) any later
21 * version.
22 *
23 * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
24 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
25 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
26 * details.
27 *
28 * You should have received a copy of the GNU General Public License along
29 * with FORM. If not, see <http://www.gnu.org/licenses/>.
30 */
31/* #] License : */
32/*
33 #[ Includes :
34
35 File contains the routines for the tree structure of sparse tables
36 We insert elements by
37 InsTableTree(T,tp) with T the TABLES element and tp the pointer
38 to the indices.
39 We look for elements with
40 FindTableTree(T,tp,inc) with T the TABLES element, tp the pointer to the
41 indices or the function arguments and inc tells which of these options.
42 The tree is cleared with ClearTableTree(T) and we rebuild the tree
43 after a .store in which we lost a part of the table with
44 RedoTableTree(T,newsize)
45
46 In T->tablepointers we have the lists of indices for each element.
47 Additionally for each element there is an extension. There are
48 TABLEEXTENSION WORDs reserved for that. The old system had two words
49 One for the element in the rhs of the compile buffer and one for
50 an additional rhs in case the original would be overwritten by a new
51 definition, but the old was fixed by .global and hence it should be possible
52 to restore it.
53 New use (new = 24-sep-2001)
54 rhs1,numCompBuffer1,rhs2,numCompBuffer2,usage
55 Hence TABLEEXTENSION will be 5. Note that for 64 bits the use of the
56 compiler buffer is overdoing it a bit, but it would be too complicated
57 to try to give it special code.
58*/
59
60#include "form3.h"
61#include "minos.h"
62#include "comtool.h"
63
64/* static UBYTE *sparse = (UBYTE *)"sparse"; */
65static UBYTE *tablebase = (UBYTE *)"tablebase";
66
67/*
68 #] Includes :
69 #[ ClearTableTree :
70*/
71
72void ClearTableTree(TABLES T)
73{
74 COMPTREE *root;
75 if ( T->boomlijst == 0 ) {
76 T->MaxTreeSize = 125;
77 T->boomlijst = (COMPTREE *)Malloc1(T->MaxTreeSize*sizeof(COMPTREE),
78 "ClearTableTree");
79 }
80 root = T->boomlijst;
81 T->numtree = 0;
82 T->rootnum = 0;
83 root->left = -1;
84 root->right = -1;
85 root->parent = -1;
86 root->blnce = 0;
87 root->value = -1;
88 root->usage = 0;
89}
90
91/*
92 #] ClearTableTree :
93 #[ InsTableTree :
94
95 int InsTableTree(TABLES T,WORD *,arglist)
96 Searches for the element specified by the list of arguments.
97 If found, it returns -(the offset in T->tablepointers)
98 If not found, it will allocate a new element, balance the tree if
99 necessary and return the number of the element in the boomlijst
100 This number is always > 0, because we start from 1.
101*/
102
103int InsTableTree(TABLES T, WORD *tp)
104{
105 COMPTREE *boomlijst, *q, *p, *s;
106 WORD *v1, *v2, *v3, xstop;
107 int ip, iq, is;
108 if ( T->numtree + 1 >= T->MaxTreeSize ) {
109 if ( T->MaxTreeSize == 0 ) ClearTableTree(T);
110 else {
111 is = T->MaxTreeSize * 2;
112 s = (COMPTREE *)Malloc1(is*sizeof(COMPTREE),"InsTableTree");
113 for ( ip = 0; ip < T->MaxTreeSize; ip++ ) { s[ip] = T->boomlijst[ip]; }
114 if ( T->boomlijst ) M_free(T->boomlijst,"InsTableTree");
115 T->boomlijst = s;
116 T->MaxTreeSize = is;
117 }
118 }
119 boomlijst = T->boomlijst;
120 q = boomlijst + T->rootnum;
121 if ( q->right == -1 ) { /* First element */
122 T->numtree++;
123 s = boomlijst+T->numtree;
124 q->right = T->numtree;
125 s->parent = T->rootnum;
126 s->left = s->right = -1;
127 s->blnce = 0;
128 s->value = tp - T->tablepointers;
129 s->usage = 0;
130 return(T->numtree);
131 }
132 ip = q->right;
133 if ( T->numind >= 0 ) xstop = T->numind;
134 else xstop = *tp + 1;
135 while ( ip >= 0 ) {
136 p = boomlijst + ip;
137 v1 = T->tablepointers + p->value;
138 v2 = tp; v3 = tp + xstop;
139 while ( *v1 == *v2 && v2 < v3 ) { v1++; v2++; }
140 if ( v2 >= v3 ) return(-p->value);
141 if ( *v1 > *v2 ) {
142 iq = p->right;
143 if ( iq >= 0 ) { ip = iq; }
144 else {
145 T->numtree++;
146 is = T->numtree;
147 p->right = is;
148 s = boomlijst + is;
149 s->parent = ip; s->left = s->right = -1;
150 s->blnce = 0; s->value = tp - T->tablepointers;
151 s->usage = 0;
152 p->blnce++;
153 if ( p->blnce == 0 ) return(T->numtree);
154 goto balance;
155 }
156 }
157 else if ( *v1 < *v2 ) {
158 iq = p->left;
159 if ( iq >= 0 ) { ip = iq; }
160 else {
161 T->numtree++;
162 is = T->numtree;
163 s = boomlijst+is;
164 p->left = is;
165 s->parent = ip; s->left = s->right = -1;
166 s->blnce = 0; s->value = tp - T->tablepointers;
167 s->usage = 0;
168 p->blnce--;
169 if ( p->blnce == 0 ) return(T->numtree);
170 goto balance;
171 }
172 }
173 }
174 MesPrint("Serious problems in InsTableTree!\n");
175 Terminate(-1);
176 return(0);
177balance:;
178 for (;;) {
179 p = boomlijst + ip;
180 iq = p->parent;
181 if ( iq == T->rootnum ) break;
182 q = boomlijst + iq;
183 if ( ip == q->left ) q->blnce--;
184 else q->blnce++;
185 if ( q->blnce == 0 ) break;
186 if ( q->blnce == -2 ) {
187 if ( p->blnce == -1 ) { /* single rotation */
188 q->left = p->right;
189 p->right = iq;
190 p->parent = q->parent;
191 q->parent = ip;
192 if ( boomlijst[p->parent].left == iq ) boomlijst[p->parent].left = ip;
193 else boomlijst[p->parent].right = ip;
194 if ( q->left >= 0 ) boomlijst[q->left].parent = iq;
195 q->blnce = p->blnce = 0;
196 }
197 else { /* double rotation */
198 s = boomlijst + is;
199 q->left = s->right;
200 p->right = s->left;
201 s->right = iq;
202 s->left = ip;
203 if ( p->right >= 0 ) boomlijst[p->right].parent = ip;
204 if ( q->left >= 0 ) boomlijst[q->left].parent = iq;
205 s->parent = q->parent;
206 q->parent = is;
207 p->parent = is;
208 if ( boomlijst[s->parent].left == iq )
209 boomlijst[s->parent].left = is;
210 else boomlijst[s->parent].right = is;
211 if ( s->blnce > 0 ) { q->blnce = s->blnce = 0; p->blnce = -1; }
212 else if ( s->blnce < 0 ) { p->blnce = s->blnce = 0; q->blnce = 1; }
213 else { p->blnce = s->blnce = q->blnce = 0; }
214 }
215 break;
216 }
217 else if ( q->blnce == 2 ) {
218 if ( p->blnce == 1 ) { /* single rotation */
219 q->right = p->left;
220 p->left = iq;
221 p->parent = q->parent;
222 q->parent = ip;
223 if ( boomlijst[p->parent].left == iq ) boomlijst[p->parent].left = ip;
224 else boomlijst[p->parent].right = ip;
225 if ( q->right >= 0 ) boomlijst[q->right].parent = iq;
226 q->blnce = p->blnce = 0;
227 }
228 else { /* double rotation */
229 s = boomlijst + is;
230 q->right = s->left;
231 p->left = s->right;
232 s->left = iq;
233 s->right = ip;
234 if ( p->left >= 0 ) boomlijst[p->left].parent = ip;
235 if ( q->right >= 0 ) boomlijst[q->right].parent = iq;
236 s->parent = q->parent;
237 q->parent = is;
238 p->parent = is;
239 if ( boomlijst[s->parent].left == iq ) boomlijst[s->parent].left = is;
240 else boomlijst[s->parent].right = is;
241 if ( s->blnce < 0 ) { q->blnce = s->blnce = 0; p->blnce = 1; }
242 else if ( s->blnce > 0 ) { p->blnce = s->blnce = 0; q->blnce = -1; }
243 else { p->blnce = s->blnce = q->blnce = 0; }
244 }
245 break;
246 }
247 is = ip; ip = iq;
248 }
249 return(T->numtree);
250}
251
252/*
253 #] InsTableTree :
254 #[ RedoTableTree :
255
256 To be used when a sparse table is trimmed due to a .store
257 We rebuild the tree. In the future one could try to become faster
258 at the cost of quite some complexity.
259 We need to keep the first 'size' elements in the boomlijst.
260 Kill all others and reconstruct the tree with the original ordering.
261 This is very complicated! Because .store will either keep the whole
262 table or remove the whole table we should not come here often.
263 Hence we choose the slow solution for now.
264*/
265
266void RedoTableTree(TABLES T, int newsize)
267{
268 WORD *tp;
269 int i;
270 ClearTableTree(T);
271 for ( i = 0, tp = T->tablepointers; i < newsize; i++ ) {
272 InsTableTree(T,tp);
273 tp += ABS(T->numind)+TABLEEXTENSION;
274 }
275}
276
277/*
278 #] RedoTableTree :
279 #[ FindTableTree :
280
281 int FindTableTree(TABLES T,WORD *,arglist,int,inc)
282 Searches for the element specified by the list of arguments.
283 If found, it returns the offset in T->tablepointers
284 If not found, it will return -1
285 The list here is from the list of function arguments. Hence it
286 has pairs of numbers -SNUMBER,index
287 Actually inc says how many numbers there are and the above case is
288 for inc = 2. For inc = 1 we have just a list of indices.
289*/
290
291int FindTableTree(TABLES T, WORD *tp, int inc)
292{
293 COMPTREE *boomlijst = T->boomlijst, *q = boomlijst + T->rootnum, *p;
294 WORD *v1, *v2, *v3, xstop;
295 int ip, iq;
296 if ( q->right == -1 ) return(-1);
297 ip = q->right;
298 if ( inc > 1 ) tp += inc-1;
299 if ( T->numind >= 0 ) xstop = T->numind;
300 else { /* We have to read the number of arguments first */
301 if ( *tp <= 0 ) return(-1); /* Cannot be! */
302 xstop = *tp+1;
303 }
304 while ( ip >= 0 ) {
305 p = boomlijst + ip;
306 v1 = T->tablepointers + p->value;
307 v2 = tp; v3 = v1 + xstop;
308 while ( *v1 == *v2 && v1 < v3 ) { v1++; v2 += inc; }
309 if ( v1 == v3 ) {
310 p->usage++;
311 return(p->value);
312 }
313 if ( *v1 > *v2 ) {
314 iq = p->right;
315 if ( iq >= 0 ) { ip = iq; }
316 else return(-1);
317 }
318 else if ( *v1 < *v2 ) {
319 iq = p->left;
320 if ( iq >= 0 ) { ip = iq; }
321 else return(-1);
322 }
323 }
324 MesPrint("Serious problems in FindTableTree\n");
325 Terminate(-1);
326 return(-1);
327}
328
329/*
330 #] FindTableTree :
331 #[ DoTableExpansion :
332*/
333
334int DoTableExpansion(WORD *term, WORD level)
335{
336 GETIDENTITY
337 WORD *t, *tstop, *stopper, *termout, *m, *mm, *tp, *r, xx;
338 WORD numsubexp, numbuf;
339 TABLES T = 0;
340 int i, j, num;
341 AN.TeInFun = AR.TePos = 0;
342 tstop = term + *term;
343 stopper = tstop - ABS(tstop[-1]);
344 t = term+1;
345 while ( t < stopper ) {
346 if ( *t != TABLEFUNCTION ) { t += t[1]; continue; }
347 if ( t[FUNHEAD] > -FUNCTION ) { t += t[1]; continue; }
348 T = functions[-t[FUNHEAD]-FUNCTION].tabl;
349 if ( T == 0 ) { t += t[1]; continue; }
350 if ( T->spare ) T = T->spare;
351 if ( t[1] == FUNHEAD+2 && t[FUNHEAD+1] <= -FUNCTION ) break;
352 if ( t[1] < FUNHEAD+1+2*ABS(T->numind) ) { t += t[1]; continue; }
353 for ( i = 0; i < ABS(T->numind); i++ ) {
354 if ( t[FUNHEAD+1+2*i] != -SYMBOL ) break;
355 }
356 if ( i >= ABS(T->numind) ) break;
357 t += t[1];
358 }
359 if ( t >= stopper ) {
360 MesPrint("Internal error: Missing table_ function");
361 Terminate(-1);
362 }
363/*
364 Table in T. Now collect the numbers of the symbols;
365*/
366 termout = AT.WorkPointer;
367 if ( T->sparse ) {
368 for ( i = 0; i < T->totind; i++ ) {
369/*
370 Loop over all table elements
371*/
372 m = termout + 1; mm = term + 1;
373 while ( mm < t ) *m++ = *mm++;
374 r = m;
375 if ( t[1] == FUNHEAD+2 && t[FUNHEAD+1] <= -FUNCTION ) {
376 *m++ = -t[FUNHEAD+1];
377 tp = T->tablepointers + (ABS(T->numind)+TABLEEXTENSION)*i;
378 if ( T->numind < 0 ) {
379 xx = tp[0]+1;
380 *m++ = FUNHEAD+xx*2;
381 for ( j = 2; j < FUNHEAD; j++ ) *m++ = 0;
382 for ( j = 0; j < xx; j++ ) {
383 *m++ = -SNUMBER; *m++ = *tp++;
384 }
385 }
386 else {
387 *m++ = FUNHEAD+T->numind*2;
388 for ( j = 2; j < FUNHEAD; j++ ) *m++ = 0;
389 for ( j = 0; j < T->numind; j++ ) {
390 *m++ = -SNUMBER; *m++ = *tp++;
391 }
392 }
393 }
394 else if ( T->numind < 0 ) {
395 tp = T->tablepointers + (ABS(T->numind)+TABLEEXTENSION)*i;
396 xx = tp[0]+1;
397 *m++ = SYMBOL; *m++ = 2+xx*2; mm = t + FUNHEAD+1;
398 for ( j = 0; j < xx; j++, mm += 2, tp++ ) {
399 if ( *tp != 0 ) { *m++ = mm[1]; *m++ = *tp; }
400 }
401 r[1] = m-r;
402 if ( r[1] == 2 ) m = r;
403 }
404 else {
405 *m++ = SYMBOL; *m++ = 2+T->numind*2; mm = t + FUNHEAD+1;
406 tp = T->tablepointers + (T->numind+TABLEEXTENSION)*i;
407 for ( j = 0; j < T->numind; j++, mm += 2, tp++ ) {
408 if ( *tp != 0 ) { *m++ = mm[1]; *m++ = *tp; }
409 }
410 r[1] = m-r;
411 if ( r[1] == 2 ) m = r;
412 }
413/*
414 The next code replaces this old code
415
416 *m++ = SUBEXPRESSION;
417 *m++ = SUBEXPSIZE;
418 *m++ = *tp;
419 *m++ = 1;
420 *m++ = T->bufnum;
421 FILLSUB(m);
422 mm = t + t[1];
423
424 We had forgotten to take the parameters into account.
425 Hence the subexpression prototype for wildcards was missed
426 Now we slow things down a little bit, but we do not run
427 any risks. There is still one problem. We have not checked
428 that the prototype matches.
429*/
430 tp = T->tablepointers + (ABS(T->numind)+TABLEEXTENSION)*i
431 +ABS(T->numind);
432 numsubexp = tp[0]; numbuf = tp[1];
433 r = m;
434#ifdef WITHPTHREADS
435 tp = T->prototype[identity];
436#else
437 tp = T->prototype;
438#endif
439 for ( j = 0; j < tp[1]; j++ ) *m++ = tp[j];
440 r[2] = numsubexp; r[4] = numbuf;
441/*
442 r = m;
443 tp = T->tablepointers + (ABS(T->numind)+TABLEEXTENSION)*i;
444 *m++ = -t[FUNHEAD];
445 if ( T->numind < 0 ) {
446 xx = tp[0]+1;
447 *m++ = t[1] - xx - T->numind - 1;
448 }
449 else {
450 xx = T->numind;
451 *m++ = t[1] - 1;
452 }
453 for ( j = 2; j < FUNHEAD; j++ ) *m++ = t[j];
454 for ( j = 0; j < xx; j++ ) {
455 *m++ = -SNUMBER; *m++ = *tp++;
456 }
457 tp = t + FUNHEAD + 1 + 2*T->numind;
458 mm = t + t[1];
459 while ( tp < mm ) *m++ = *tp++;
460 r[1] = m-r;
461*/
462/*
463 From now on is old code
464*/
465 mm = t + t[1];
466 while ( mm < tstop ) *m++ = *mm++;
467 *termout = m - termout;
468 AT.WorkPointer = m;
469 if ( Generator(BHEAD termout,level) ) {
470 MesCall("DoTableExpand");
471 return(-1);
472 }
473 AT.WorkPointer = termout;
474 }
475 }
476 else {
477 for ( i = 0; i < T->totind; i++ ) {
478#if TABLEEXTENSION == 2
479 if ( T->tablepointers[i] < 0 ) continue;
480#else
481 if ( T->tablepointers[TABLEEXTENSION*i] < 0 ) continue;
482#endif
483 m = termout + 1; mm = term + 1;
484 while ( mm < t ) *m++ = *mm++;
485 r = m;
486 if ( t[1] == FUNHEAD+2 && t[FUNHEAD+1] <= -FUNCTION ) {
487 *m++ = -t[FUNHEAD+1];
488 *m++ = FUNHEAD+T->numind*2;
489 for ( j = 2; j < FUNHEAD; j++ ) *m++ = 0;
490 tp = T->tablepointers + (T->numind+TABLEEXTENSION)*i;
491 for ( j = 0; j < T->numind; j++ ) {
492 if ( j > 0 ) {
493 num = T->mm[j].mini + ( i % T->mm[j-1].size ) / T->mm[j].size;
494 }
495 else {
496 num = T->mm[j].mini + i / T->mm[j].size;
497 }
498 *m++ = -SNUMBER; *m++ = num;
499 }
500 }
501 else {
502 *m++ = SYMBOL; *m++ = 2+T->numind*2; mm = t + FUNHEAD+1;
503 for ( j = 0; j < T->numind; j++, mm += 2 ) {
504 if ( j > 0 ) {
505 num = T->mm[j].mini + ( i % T->mm[j-1].size ) / T->mm[j].size;
506 }
507 else {
508 num = T->mm[j].mini + i / T->mm[j].size;
509 }
510 if ( num != 0 ) { *m++ = mm[1]; *m++ = num; }
511 }
512 r[1] = m-r;
513 if ( r[1] == 2 ) m = r;
514 }
515/*
516 The next code replaces this old code
517
518 *m++ = SUBEXPRESSION;
519 *m++ = SUBEXPSIZE;
520 *m++ = *tp;
521 *m++ = 1;
522 *m++ = T->bufnum;
523 FILLSUB(m);
524 mm = t + t[1];
525
526 We had forgotten to take the parameters into account.
527 Hence the subexpression prototype for wildcards was missed
528 Now we slow things down a little bit, but we do not run
529 any risks. There is still one problem. We have not checked
530 that the prototype matches.
531*/
532 r = m;
533 *m++ = -t[FUNHEAD];
534 *m++ = t[1] - 1;
535 for ( j = 2; j < FUNHEAD; j++ ) *m++ = t[j];
536 for ( j = 0; j < T->numind; j++ ) {
537 if ( j > 0 ) {
538 num = T->mm[j].mini + ( i % T->mm[j-1].size ) / T->mm[j].size;
539 }
540 else {
541 num = T->mm[j].mini + i / T->mm[j].size;
542 }
543 *m++ = -SNUMBER; *m++ = num;
544 }
545 tp = t + FUNHEAD + 1 + 2*T->numind;
546 mm = t + t[1];
547 while ( tp < mm ) *m++ = *tp++;
548 r[1] = m - r;
549/*
550 From now on is old code
551*/
552 while ( mm < tstop ) *m++ = *mm++;
553 *termout = m - termout;
554 AT.WorkPointer = m;
555 if ( Generator(BHEAD termout,level) ) {
556 MesCall("DoTableExpand");
557 return(-1);
558 }
559 }
560 }
561 return(0);
562}
563
564/*
565 #] DoTableExpansion :
566 #[ TableBase :
567
568 File with all the database related things.
569 We have the routines for the generic database command
570 TableBase,options;
571 TB,options;
572 Options are:
573 Open "File.tbl"; Open for R/W
574 Open "File.tbl", readonly; Open for R
575 Create "File.tbl"; Create for write
576 Load "File.tbl", tablename; Loads stubs of table
577 Load "File.tbl"; Loads stubs of all tables
578 Enter "File.tbl", tablename; Loads whole table
579 Enter "File.tbl"; Loads all tables
580 Audit "File.tbl", options; Print list of contents
581 Replace "File.tbl", tablename; Saves a table (with overwrite)
582 Replace "File.tbl", table element; Saves a table element ,,
583 Cleanup "File.tbl"; Makes tables contingent
584 AddTo "File.tbl" tablename; Add if not yet there.
585 AddTo "File.tbl" table element; Add if not yet there.
586 Delete "File.tbl" tablename;
587 Delete "File.tbl" table element;
588
589 On/Off substitute;
590 On/Off compress "File.tbl";
591 id tbl_(f?,?a) = f(?a);
592 When a tbl_ is used, automatically the corresponding element is compiled
593 at the start of the next module.
594 if TB,On,substitute [tablename], use of table RHS (if loaded)
595 if TB,Off,substitute [tablename], use of tbl_(table,...);
596
597
598 Still needed: Something like OverLoad to allow loading parts of a table
599 from more than one file. Date stamps needed? In that case we need a touch
600 command as well.
601
602 If we put all our diagrams inside, we have to go outside the concept
603 of tables.
604
605 #] TableBase :
606 #[ CoTableBase :
607
608 To be followed by ,subkey
609*/
610static KEYWORD tboptions[] = {
611 {"addto", (TFUN)CoTBaddto, 0, PARTEST}
612 ,{"audit", (TFUN)CoTBaudit, 0, PARTEST}
613 ,{"cleanup", (TFUN)CoTBcleanup, 0, PARTEST}
614 ,{"create", (TFUN)CoTBcreate, 0, PARTEST}
615 ,{"enter", (TFUN)CoTBenter, 0, PARTEST}
616 ,{"help", (TFUN)CoTBhelp, 0, PARTEST}
617 ,{"load", (TFUN)CoTBload, 0, PARTEST}
618 ,{"off", (TFUN)CoTBoff, 0, PARTEST}
619 ,{"on", (TFUN)CoTBon, 0, PARTEST}
620 ,{"open", (TFUN)CoTBopen, 0, PARTEST}
621 ,{"replace", (TFUN)CoTBreplace, 0, PARTEST}
622 ,{"use", (TFUN)CoTBuse, 0, PARTEST}
623};
624
625static UBYTE *tablebasename = 0;
626
627int CoTableBase(UBYTE *s)
628{
629 UBYTE *option, c, *t;
630 int i,optlistsize = sizeof(tboptions)/sizeof(KEYWORD), error = 0;
631 while ( *s == ' ' ) s++;
632 if ( *s != '"' ) {
633 if ( ( tolower(*s) == 'h' ) && ( tolower(s[1]) == 'e' )
634 && ( tolower(s[2]) == 'l' ) && ( tolower(s[3]) == 'p' )
635 && ( FG.cTable[s[4]] > 1 ) ) {
636 CoTBhelp(s);
637 return(0);
638 }
639proper:;
640 MesPrint("&Proper syntax: TableBase \"filename\" options");
641 return(1);
642 }
643 s++; tablebasename = s;
644 while ( *s && *s != '"' ) s++;
645 if ( *s != '"' ) goto proper;
646 t = s; s++; *t = 0;
647 while ( *s == ' ' || *s == '\t' || *s == ',' ) s++;
648 option = s;
649 while ( FG.cTable[*s] == 0 ) s++;
650 c = *s; *s = 0;
651 for ( i = 0; i < optlistsize; i++ ) {
652 if ( StrICmp(option,(UBYTE *)(tboptions[i].name)) == 0 ) {
653 *s = c;
654 while ( *s == ',' ) s++;
655 error = (tboptions[i].func)(s);
656 *t = '"';
657 return(error);
658 }
659 }
660 MesPrint("&Unrecognized option %s in TableBase statement",option);
661 return(1);
662}
663
664/*
665 #] CoTableBase :
666 #[ FlipTable :
667
668 Flips the table between use as 'stub' and regular use
669*/
670
671int FlipTable(FUNCTIONS f, int type)
672{
673 TABLES T, TT;
674 T = f->tabl;
675 if ( ( TT = T->spare ) == 0 ) {
676 MesPrint("Error: trying to change mode on a table that has no tablebase");
677 return(-1);
678 }
679 if ( TT->mode == type ) f->tabl = TT;
680 return(0);
681}
682
683/*
684 #] FlipTable :
685 #[ SpareTable :
686
687 Creates a spare element for a table. This is used in the table bases.
688 It is a (thus far) empty copy of the TT table.
689 By using FlipTable we can switch between them and alter which version of
690 a table we will be using. Note that this also causes some extra work in the
691 ResetVariables and the Globalize routines.
692*/
693
694int SpareTable(TABLES TT)
695{
696 TABLES T;
697 T = (TABLES)Malloc1(sizeof(struct TaBlEs),"table");
698 T->defined = T->mdefined = 0; T->sparse = TT->sparse; T->mm = 0; T->flags = 0;
699 T->numtree = 0; T->rootnum = 0; T->MaxTreeSize = 0;
700 T->boomlijst = 0;
701 T->strict = TT->strict;
702 T->bounds = TT->bounds;
703 T->bufnum = inicbufs();
704 T->argtail = TT->argtail;
705 T->spare = TT;
706 T->bufferssize = 8;
707 T->buffers = (WORD *)Malloc1(sizeof(WORD)*T->bufferssize,"SpareTable buffers");
708 T->buffersfill = 0;
709 T->buffers[T->buffersfill++] = T->bufnum;
710 T->mode = 0;
711 T->numind = TT->numind;
712 T->totind = 0;
713 T->prototype = TT->prototype;
714 T->pattern = TT->pattern;
715 T->tablepointers = 0;
716 T->reserved = 0;
717 T->tablenum = 0;
718 T->numdummies = 0;
719 T->mm = (MINMAX *)Malloc1(ABS(T->numind)*sizeof(MINMAX),"table dimensions");
720 T->flags = (WORD *)Malloc1(ABS(T->numind)*sizeof(WORD),"table flags");
721 ClearTableTree(T);
722 TT->spare = T;
723 TT->mode = 1;
724 return(0);
725}
726
727/*
728 #] SpareTable :
729 #[ FindTB :
730
731 Looks for a tablebase with the given name in the active tablebases.
732*/
733
734DBASE *FindTB(UBYTE *name)
735{
736 DBASE *d;
737 int i;
738 for ( i = 0; i < NumTableBases; i++ ) {
739 d = tablebases+i;
740 if ( d->name && ( StrCmp(name,(UBYTE *)(d->name)) == 0 ) ) { return(d); }
741 }
742 return(0);
743}
744
745/*
746 #] FindTB :
747 #[ CoTBcreate :
748
749 Creates a new tablebase.
750 Error is when there is already an active tablebase by this name.
751 If a file with the given name exists already, but it does not correspond
752 to an active table base, its contents will be lost.
753 Note that tablebasename is a static variable, defined in CoTableBase
754*/
755
756int CoTBcreate(UBYTE *s)
757{
758 DUMMYUSE(s);
759 if ( FindTB(tablebasename) != 0 ) {
760 MesPrint("&There is already an open TableBase with the name %s",tablebasename);
761 return(-1);
762 }
763 NewDbase((char *)tablebasename,0);
764 return(0);
765}
766
767/*
768 #] CoTBcreate :
769 #[ CoTBopen :
770*/
771
772int CoTBopen(UBYTE *s)
773{
774 DBASE *d;
775 MLONG rw = 1;
776
777 SkipSpaces(&s);
778
779 if ( *s ) {
780 if ( ConsumeOption(&s,"readonly") != 0 ) {
781 rw = 0;
782 } else {
783 MesPrint("&Invalid option for TableBase open: %s, ignoring", s);
784 }
785 }
786
787 if ( ( d = FindTB(tablebasename) ) != 0 ) {
788 MesPrint("&There is already an open TableBase with the name %s",tablebasename);
789 return(-1);
790 }
791 d = GetDbase((char *)tablebasename, rw);
792 if ( CheckTableDeclarations(d) ) return(-1);
793 return(0);
794}
795
796/*
797 #] CoTBopen :
798 #[ CoTBaddto :
799*/
800
801int CoTBaddto(UBYTE *s)
802{
803 GETIDENTITY
804 DBASE *d;
805 UBYTE *tablename, c, *t, elementstring[ELEMENTSIZE+20], *ss, *es;
806 WORD type, funnum, lbrac, first, num, *expr, *w;
807 TABLES T = 0;
808 MLONG basenumber;
809 LONG x;
810 int i, j, error = 0, sum;
811 if ( ( d = FindTB(tablebasename) ) == 0 ) {
812 MesPrint("&No open tablebase with the name %s",tablebasename);
813 return(-1);
814 }
815
816 if ( ( d->rwmode ) == 0 ) {
817 MesPrint("&Tablebase with the name %s opened in read only mode",tablebasename);
818 return(-1);
819 }
820 AO.DollarOutSizeBuffer = 32;
821 AO.DollarOutBuffer = (UBYTE *)Malloc1(AO.DollarOutSizeBuffer,
822 "TableOutBuffer");
823/*
824 Now loop through the names and start adding
825*/
826 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
827 while ( *s ) {
828 tablename = s;
829 if ( ( s = SkipAName(s) ) == 0 ) goto tableabort;
830 c = *s; *s = 0;
831 if ( ( GetVar(tablename,&type,&funnum,CFUNCTION,NOAUTO) == NAMENOTFOUND )
832 || ( T = functions[funnum].tabl ) == 0 ) {
833 MesPrint("&%s should be a previously declared table",tablename);
834 *s = c; goto tableabort;
835 }
836 if ( T->sparse == 0 ) {
837 MesPrint("&%s should be a sparse table",tablename);
838 *s = c; goto tableabort;
839 }
840 basenumber = AddTableName(d,(char *)tablename,T);
841 if ( T->spare && ( T->mode == 1 ) ) T = T->spare;
842 if ( basenumber < 0 ) basenumber = -basenumber;
843 else if ( basenumber == 0 ) { *s = c; goto tableabort; }
844 *s = c;
845 if ( *s == '(' ) { /* Addition of single element */
846 s++; es = s;
847 for ( i = 0, w = AT.WorkPointer; i < ABS(T->numind); i++ ) {
848 ParseSignedNumber(x,s);
849 if ( FG.cTable[s[-1]] != 1 || ( *s != ',' && *s != ')' ) ) {
850 MesPrint("&Table arguments in TableBase addto statement should be numbers");
851 return(1);
852 }
853 *w++ = x;
854 if ( *s == ')' ) break;
855 s++;
856 }
857 if ( *s != ')' || i < ( ABS(T->numind) - 1 ) ) {
858 MesPrint("&Incorrect number of table arguments in TableBase addto statement. Should be %d"
859 ,ABS(T->numind));
860 error = 1;
861 }
862 c = *s; *s = 0;
863 i = FindTableTree(T,AT.WorkPointer,1);
864 if ( i < 0 ) {
865 MesPrint("&Element %s has not been defined",es);
866 error = 1;
867 *s++ = c;
868 }
869 else if ( ExistsObject(d,basenumber,(char *)es) ) {}
870 else {
871 int dict = AO.CurrentDictionary;
872 AO.CurrentDictionary = 0;
873 sum = i + ABS(T->numind);
874/*
875 See also commentary below
876*/
877 AO.DollarInOutBuffer = 1;
878 AO.PrintType = 1;
879 ss = AO.DollarOutBuffer;
880 *ss = 0;
881 AO.OutInBuffer = 1;
882#if ( TABLEEXTENSION == 2 )
883 expr = cbuf[T->bufnum].rhs[T->tablepointers[sum]];
884#else
885 expr = cbuf[T->tablepointers[sum+1]].rhs[T->tablepointers[sum]];
886#endif
887 lbrac = 0; first = 0;
888 while ( *expr ) {
889 if ( WriteTerm(expr,&lbrac,first,PRINTON,0) ) {
890 error = 1; break;
891 }
892 expr += *expr;
893 }
894 AO.OutInBuffer = 0;
895 AddObject(d,basenumber,(char *)es,(char *)(AO.DollarOutBuffer));
896 *s++ = c;
897 AO.CurrentDictionary = dict;
898 }
899 }
900 else {
901/*
902 Now we have to start looping through all defined elements of this table.
903 We have to construct the arguments in text format.
904*/
905 for ( i = 0; i < T->totind; i++ ) {
906#if ( TABLEEXTENSION == 2 )
907 if ( !T->sparse && T->tablepointers[i] < 0 ) continue;
908#else
909 if ( !T->sparse && T->tablepointers[TABLEEXTENSION*i] < 0 ) continue;
910#endif
911 sum = i * ( ABS(T->numind) + TABLEEXTENSION );
912 t = elementstring;
913 for ( j = 0; j < ABS(T->numind); j++, sum++ ) {
914 if ( j > 0 ) *t++ = ',';
915 num = T->tablepointers[sum];
916 t = NumCopy(num,t);
917 if ( ( t - elementstring ) >= ELEMENTSIZE ) {
918 MesPrint("&Table element specification takes more than %ld characters and cannot be handled",
919 (MLONG)ELEMENTSIZE);
920 goto tableabort;
921 }
922 }
923 if ( ExistsObject(d,basenumber,(char *)elementstring) ) { continue; }
924/*
925 We have the number in basenumber and the element in elementstring.
926 Now we need the rhs. We can use the code from WriteDollarToBuffer.
927 Main complication: in the table compiler buffer there can be
928 brackets. The dollars do not have those......
929*/
930 AO.DollarInOutBuffer = 1;
931 AO.PrintType = 1;
932 ss = AO.DollarOutBuffer;
933 *ss = 0;
934 AO.OutInBuffer = 1;
935#if ( TABLEEXTENSION == 2 )
936 expr = cbuf[T->bufnum].rhs[T->tablepointers[sum]];
937#else
938 expr = cbuf[T->tablepointers[sum+1]].rhs[T->tablepointers[sum]];
939#endif
940 lbrac = 0; first = 0;
941 while ( *expr ) {
942 if ( WriteTerm(expr,&lbrac,first,PRINTON,0) ) {
943 error = 1; break;
944 }
945 expr += *expr;
946 }
947 AO.OutInBuffer = 0;
948 AddObject(d,basenumber,(char *)elementstring,(char *)(AO.DollarOutBuffer));
949 }
950 }
951 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
952 }
953 if ( WriteIniInfo(d) ) goto tableabort;
954 M_free(AO.DollarOutBuffer,"DollarOutBuffer");
955 AO.DollarOutBuffer = 0;
956 AO.DollarOutSizeBuffer = 0;
957 return(error);
958tableabort:;
959 M_free(AO.DollarOutBuffer,"DollarOutBuffer");
960 AO.DollarOutBuffer = 0;
961 AO.DollarOutSizeBuffer = 0;
962 AO.OutInBuffer = 0;
963 return(1);
964}
965
966/*
967 #] CoTBaddto :
968 #[ CoTBenter :
969
970 Loads the elements of the tables specified into memory and sends them
971 one by one to the compiler as Fill statements.
972*/
973
974int CoTBenter(UBYTE *s)
975{
976 DBASE *d;
977 MLONG basenumber;
978 UBYTE *arguments, *rhs, *buffer, *t, *u, c, *tablename;
979 LONG size;
980 int i, j, error = 0, error1 = 0, printall = 0;
981 TABLES T = 0;
982 WORD type, funnum;
983 int dict = AO.CurrentDictionary;
984 AO.CurrentDictionary = 0;
985 if ( ( d = FindTB(tablebasename) ) == 0 ) {
986 MesPrint("&No open tablebase with the name %s, check for existence of file or try readonly mode when opening.",tablebasename);
987 error = -1;
988 goto Endofall;
989 }
990 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
991 if ( *s == '!' ) { printall = 1; s++; }
992 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
993 if ( *s ) {
994 while ( *s ) {
995 tablename = s;
996 if ( ( s = SkipAName(s) ) == 0 ) { error = 1; goto Endofall; }
997 c = *s; *s = 0;
998 if ( ( GetVar(tablename,&type,&funnum,CFUNCTION,NOAUTO) == NAMENOTFOUND )
999 || ( T = functions[funnum].tabl ) == 0 ) {
1000 MesPrint("&%s should be a previously declared table",tablename);
1001 basenumber = 0;
1002 }
1003 else if ( T->sparse == 0 ) {
1004 MesPrint("&%s should be a sparse table",tablename);
1005 basenumber = 0;
1006 }
1007 else { basenumber = GetTableName(d,(char *)tablename); }
1008 if ( T->spare == 0 ) { SpareTable(T); }
1009 if ( basenumber > 0 ) {
1010 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1011 for ( j = 0; j < NUMOBJECTS; j++ ) {
1012 if ( basenumber != d->iblocks[i]->objects[j].tablenumber )
1013 continue;
1014 arguments = (UBYTE *)(d->iblocks[i]->objects[j].element);
1015 rhs = (UBYTE *)ReadObject(d,basenumber,(char *)arguments);
1016 if ( printall ) {
1017 if ( rhs ) {
1018 MesPrint("%s(%s) = %s",tablename,arguments,rhs);
1019 }
1020 else {
1021 MesPrint("%s(%s) = 0",tablename,arguments);
1022 }
1023 }
1024 if ( rhs ) {
1025 u = rhs; while ( *u ) u++;
1026 size = u-rhs;
1027 u = arguments; while ( *u ) u++;
1028 size += u-arguments;
1029 u = tablename; while ( *u ) u++;
1030 size += u-tablename;
1031 size += 6;
1032 buffer = (UBYTE *)Malloc1(size,"TableBase copy");
1033 t = tablename; u = buffer;
1034 while ( *t ) *u++ = *t++;
1035 *u++ = '(';
1036 t = arguments;
1037 while ( *t ) *u++ = *t++;
1038 *u++ = ')'; *u++ = '=';
1039 t = rhs;
1040 while ( *t ) *u++ = *t++;
1041 if ( t == rhs ) *u++ = '0';
1042 *u++ = 0; *u = 0;
1043 M_free(rhs,"rhs in TBenter");
1044
1045 error1 = CoFill(buffer);
1046
1047 if ( error1 < 0 ) goto Endofall;
1048 if ( error1 != 0 ) error = error1;
1049 M_free(buffer,"TableBase copy");
1050 }
1051 }
1052 }
1053 }
1054 *s = c;
1055 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
1056 }
1057 }
1058 else {
1059 s = (UBYTE *)(d->tablenames); basenumber = 0;
1060 while ( *s ) {
1061 basenumber++;
1062 tablename = s; while ( *s ) s++; s++;
1063 while ( *s ) s++;
1064 s++;
1065 if ( ( GetVar(tablename,&type,&funnum,CFUNCTION,NOAUTO) == NAMENOTFOUND )
1066 || ( T = functions[funnum].tabl ) == 0 ) {
1067 MesPrint("&%s should be a previously declared table",tablename);
1068 }
1069 else if ( T->sparse == 0 ) {
1070 MesPrint("&%s should be a sparse table",tablename);
1071 }
1072 if ( T->spare == 0 ) { SpareTable(T); }
1073 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1074 for ( j = 0; j < NUMOBJECTS; j++ ) {
1075 if ( d->iblocks[i]->objects[j].tablenumber == basenumber ) {
1076 arguments = (UBYTE *)(d->iblocks[i]->objects[j].element);
1077 rhs = (UBYTE *)ReadObject(d,basenumber,(char *)arguments);
1078 if ( printall ) {
1079 if ( rhs ) {
1080 MesPrint("%s%s = %s",tablename,arguments,rhs);
1081 }
1082 else {
1083 MesPrint("%s%s = 0",tablename,arguments);
1084 }
1085 }
1086 if ( rhs ) {
1087 u = rhs; while ( *u ) u++;
1088 size = u-rhs;
1089 u = arguments; while ( *u ) u++;
1090 size += u-arguments;
1091 u = tablename; while ( *u ) u++;
1092 size += u-tablename;
1093 size += 6;
1094 buffer = (UBYTE *)Malloc1(size,"TableBase copy");
1095 t = tablename; u = buffer;
1096 while ( *t ) *u++ = *t++;
1097 *u++ = '(';
1098 t = arguments;
1099 while ( *t ) *u++ = *t++;
1100 *u++ = ')'; *u++ = '=';
1101 t = rhs;
1102 while ( *t ) *u++ = *t++;
1103 if ( t == rhs ) *u++ = '0';
1104 *u++ = 0; *u = 0;
1105 M_free(rhs,"rhs in TBenter");
1106
1107 error1 = CoFill(buffer);
1108
1109 if ( error1 < 0 ) goto Endofall;
1110 if ( error1 != 0 ) error = error1;
1111 M_free(buffer,"TableBase copy");
1112 }
1113 }
1114 }
1115 }
1116 }
1117 }
1118Endofall:;
1119 AO.CurrentDictionary = dict;
1120 return(error);
1121}
1122
1123/*
1124 #] CoTBenter :
1125 #[ CoTestUse :
1126
1127 Possibly to be followed by names of tables.
1128 We make an array of TABLES structs to be tested in AC.usedtables.
1129 Note: only sparse tables are allowed.
1130 No arguments means all tables.
1131*/
1132
1133int CoTestUse(UBYTE *s)
1134{
1135 GETIDENTITY
1136 UBYTE *tablename, c;
1137 WORD type, funnum, *w;
1138 TABLES T;
1139 int error = 0;
1140 w = AT.WorkPointer;
1141 *w++ = TYPETESTUSE; *w++ = 2;
1142 while ( *s ) {
1143 tablename = s;
1144 if ( ( s = SkipAName(s) ) == 0 ) return(1);
1145 c = *s; *s = 0;
1146 if ( ( GetVar(tablename,&type,&funnum,CFUNCTION,NOAUTO) == NAMENOTFOUND )
1147 || ( T = functions[funnum].tabl ) == 0 ) {
1148 MesPrint("&%s should be a previously declared table",tablename);
1149 error = 1;
1150 }
1151 else if ( T->sparse == 0 ) {
1152 MesPrint("&%s should be a sparse table",tablename);
1153 error = 1;
1154 }
1155 *w++ = funnum + FUNCTION;
1156 *s = c;
1157 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1158 }
1159 AT.WorkPointer[1] = w - AT.WorkPointer;
1160/*
1161 if ( AT.WorkPointer[1] > 2 ) {
1162 AddNtoL(AT.WorkPointer[1],AT.WorkPointer);
1163 }
1164*/
1165 AddNtoL(AT.WorkPointer[1],AT.WorkPointer);
1166 return(error);
1167}
1168
1169/*
1170 #] CoTestUse :
1171 #[ CheckTableDeclarations :
1172
1173 Checks that all tables in a tablebase have identical properties to
1174 possible previous declarations. If they have not been declared
1175 before, they are declared here.
1176*/
1177
1178int CheckTableDeclarations(DBASE *d)
1179{
1180 WORD type, funnum;
1181 UBYTE *s, *ss, *t, *command = 0;
1182 int k, error = 0, error1, i;
1183 TABLES T;
1184 LONG commandsize = 0;
1185
1186 s = (UBYTE *)(d->tablenames);
1187 for ( k = 0; k < d->topnumber; k++ ) {
1188 if ( GetVar(s,&type,&funnum,ANYTYPE,NOAUTO) == NAMENOTFOUND ) {
1189/*
1190 We have to declare the table
1191*/
1192 ss = s; i = 0; while ( *ss ) { ss++; i++; } /* name */
1193 ss++; while ( *ss ) { ss++; i++; } /* tail */
1194 if ( commandsize == 0 ) {
1195 commandsize = i + 15;
1196 if ( commandsize < 100 ) commandsize = 100;
1197 }
1198 if ( (i+11) > commandsize ) {
1199 if ( command ) { M_free(command,"table command"); command = 0; }
1200 commandsize = i+10;
1201 }
1202 if ( command == 0 ) {
1203 command = (UBYTE *)Malloc1(commandsize,"table command");
1204 }
1205 t = command; ss = tablebase; while ( *ss ) *t++ = *ss++;
1206 *t++ = ','; while ( *s ) *t++ = *s++;
1207 s++; while ( *s ) *t++ = *s++;
1208 *t++ = ')'; *t = 0; s++;
1209 error1 = DoTable(command,1);
1210 if ( error1 ) error = error1;
1211 }
1212 else if ( ( type != CFUNCTION )
1213 || ( ( T = functions[funnum].tabl ) == 0 )
1214 || ( T->sparse == 0 ) ) {
1215 MesPrint("&%s has been declared previously, but not as a sparse table.",s);
1216 error = 1;
1217 while ( *s ) s++;
1218 s++;
1219 while ( *s ) s++;
1220 s++;
1221 }
1222 else {
1223/*
1224 Test dimension and argtail. There should be an exact match.
1225 We are not going to rename arguments when reading the elements.
1226*/
1227 ss = s;
1228 while ( *s ) s++;
1229 s++;
1230 if ( StrCmp(s,T->argtail) ) {
1231 MesPrint("&Declaration of table %s in %s different from previous declaration",ss,d->name);
1232 error = 1;
1233 }
1234 while ( *s ) s++;
1235 s++;
1236 }
1237 }
1238 if ( command ) { M_free(command,"table command"); }
1239 return(error);
1240}
1241
1242/*
1243 #] CheckTableDeclarations :
1244 #[ CoTBload :
1245
1246 Loads the table stubbs of the specified tables in the indicated
1247 tablebase. Syntax:
1248 TableBase "tablebasename.tbl" load [tablename(s)];
1249 If no tables are specified all tables are taken.
1250*/
1251
1252int CoTBload(UBYTE *ss)
1253{
1254 DBASE *d;
1255 UBYTE *s, *name, *t, *r, *command, *arguments, *tail;
1256 LONG commandsize;
1257 int num, cs, es, ns, ts, i, j, error = 0, error1;
1258 if ( ( d = FindTB(tablebasename) ) == 0 ) {
1259 MesPrint("&No open tablebase with the name %s",tablebasename);
1260 return(-1);
1261 }
1262 commandsize = 120;
1263 command = (UBYTE *)Malloc1(commandsize,"Fill command");
1264 AC.vetofilling = 1;
1265 if ( *ss ) {
1266 while ( *ss == ',' || *ss == ' ' || *ss == '\t' ) ss++;
1267 while ( *ss ) {
1268 name = ss; ss = SkipAName(ss); *ss = 0;
1269 s = (UBYTE *)(d->tablenames);
1270 num = 0; ns = 0;
1271 while ( *s ) {
1272 num++;
1273 if ( StrCmp(s,name) ) {
1274 while ( *s ) s++;
1275 s++;
1276 while ( *s ) s++;
1277 s++;
1278 num++;
1279 continue;
1280 }
1281 name = s; while ( *s ) s++; ns = s-name; s++;
1282 tail = s; while ( *s ) s++; ts = s-tail; s++;
1283 tail++; while ( FG.cTable[*tail] == 1 ) tail++;
1284/*
1285 Go through all elements
1286*/
1287 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1288 for ( j = 0; j < NUMOBJECTS; j++ ) {
1289 if ( d->iblocks[i]->objects[j].tablenumber == num ) {
1290 t = arguments = (UBYTE *)(d->iblocks[i]->objects[j].element);
1291 while ( *t ) t++;
1292 es = t - arguments;
1293 cs = 2*es + 2*ns + ts + 10;
1294 if ( cs > commandsize ) {
1295 commandsize = 2*cs;
1296 if ( command ) M_free(command,"Fill command");
1297 command = (UBYTE *)Malloc1(commandsize,"Fill command");
1298 }
1299 r = command; t = name; while ( *t ) *r++ = *t++;
1300 *r++ = '('; t = arguments; while ( *t ) *r++ = *t++;
1301 *r++ = ')'; *r++ = '='; *r++ = 't'; *r++ = 'b'; *r++ = 'l';
1302 *r++ = '_'; *r++ = '('; t = name; while ( *t ) *r++ = *t++;
1303 *r++ = ','; t = arguments; while ( *t ) *r++ = *t++;
1304 t = tail; while ( *t ) {
1305 if ( *t == '?' && r[-1] != ',' ) {
1306 t++;
1307 if ( FG.cTable[*t] == 0 || *t == '$' || *t == '[' ) {
1308 t = SkipAName(t);
1309 if ( *t == '[' ) {
1310 SKIPBRA1(t);
1311 }
1312 }
1313 else if ( *t == '{' ) {
1314 SKIPBRA2(t);
1315 }
1316 else if ( *t ) { *r++ = *t++; continue; }
1317 }
1318 else *r++ = *t++;
1319 }
1320 *r++ = ')'; *r = 0;
1321/*
1322 Still to do: replacemode or no replacemode?
1323*/
1324 AC.vetotablebasefill = 1;
1325 error1 = CoFill(command);
1326 AC.vetotablebasefill = 0;
1327 if ( error1 < 0 ) goto finishup;
1328 if ( error1 != 0 ) error = error1;
1329 }
1330 }
1331 }
1332 break;
1333 }
1334 while ( *ss == ',' || *ss == ' ' || *ss == '\t' ) ss++;
1335 }
1336 }
1337 else { /* do all of them */
1338 s = (UBYTE *)(d->tablenames);
1339 num = 0; ns = 0;
1340 while ( *s ) {
1341 num++;
1342 name = s; while ( *s ) s++; ns = s-name; s++;
1343 tail = s; while ( *s ) s++; ts = s-tail; s++;
1344 tail++; while ( FG.cTable[*tail] == 1 ) tail++;
1345/*
1346 Go through all elements
1347*/
1348 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1349 for ( j = 0; j < NUMOBJECTS; j++ ) {
1350 if ( d->iblocks[i]->objects[j].tablenumber == num ) {
1351 t = arguments = (UBYTE *)(d->iblocks[i]->objects[j].element);
1352 while ( *t ) t++;
1353 es = t - arguments;
1354 cs = 2*es + 2*ns + ts + 10;
1355 if ( cs > commandsize ) {
1356 commandsize = 2*cs;
1357 if ( command ) M_free(command,"Fill command");
1358 command = (UBYTE *)Malloc1(commandsize,"Fill command");
1359 }
1360 r = command; t = name; while ( *t ) *r++ = *t++;
1361 *r++ = '('; t = arguments; while ( *t ) *r++ = *t++;
1362 *r++ = ')'; *r++ = '='; *r++ = 't'; *r++ = 'b'; *r++ = 'l';
1363 *r++ = '_'; *r++ = '('; t = name; while ( *t ) *r++ = *t++;
1364 *r++ = ','; t = arguments; while ( *t ) *r++ = *t++;
1365 t = tail; while ( *t ) {
1366 if ( *t == '?' && r[-1] != ',' ) {
1367 t++;
1368 if ( FG.cTable[*t] == 0 || *t == '$' || *t == '[' ) {
1369 t = SkipAName(t);
1370 if ( *t == '[' ) {
1371 SKIPBRA1(t);
1372 }
1373 }
1374 else if ( *t == '{' ) {
1375 SKIPBRA2(t);
1376 }
1377 else if ( *t ) { *r++ = *t++; continue; }
1378 }
1379 else *r++ = *t++;
1380 }
1381 *r++ = ')'; *r = 0;
1382/*
1383 Still to do: replacemode or no replacemode?
1384*/
1385 AC.vetotablebasefill = 1;
1386 error1 = CoFill(command);
1387 AC.vetotablebasefill = 0;
1388 if ( error1 < 0 ) goto finishup;
1389 if ( error1 != 0 ) error = error1;
1390 }
1391 }
1392 }
1393 }
1394 }
1395finishup:;
1396 AC.vetofilling = 0;
1397 if ( command ) M_free(command,"Fill command");
1398 return(error);
1399}
1400
1401/*
1402 #] CoTBload :
1403 #[ TestUse :
1404
1405 Look for tbl_(tablename,arguments)
1406 if tablename is encountered, check first whether the element is in
1407 use already. If not, check in the tables in AC.usedtables.
1408 If the element is not there, add it to AC.usedtables.
1409
1410
1411 We need the arguments of TestUse to see for which tables it is to be done
1412*/
1413
1414int TestUse(WORD *term, WORD level)
1415{
1416 WORD *tstop, *t, *m, *tstart, tabnum;
1417 WORD *funs, numfuns;
1418 int error = 0;
1419 TABLES T;
1420 LONG i;
1421 CBUF *C = cbuf+AM.rbufnum;
1422 int isp;
1423
1424 numfuns = C->lhs[level][1] - 2;
1425 funs = C->lhs[level] + 2;
1426 GETSTOP(term,tstop);
1427 t = term+1;
1428 while ( t < tstop ) {
1429 if ( *t != TABLESTUB ) { t += t[1]; continue; }
1430 tstart = t;
1431 m = t + FUNHEAD;
1432 t += t[1];
1433 if ( *m >= -FUNCTION ) continue;
1434 tabnum = -*m;
1435 if ( ( T = functions[tabnum-FUNCTION].tabl ) == 0 ) continue;
1436 if ( T->sparse == 0 ) continue;
1437/*
1438 Check whether we have to test this one
1439*/
1440 if ( numfuns > 0 ) {
1441 for ( i = 0; i < numfuns; i++ ) {
1442 if ( tabnum == funs[i] ) break;
1443 }
1444 if ( i >= numfuns && numfuns > 0 ) continue;
1445 }
1446/*
1447 Test whether the element has been defined already.
1448 If not, mark it as used.
1449 Note: we only allow sparse tables (for now)
1450*/
1451 m++;
1452 for ( i = 0; i < ABS(T->numind); i++, m += 2 ) {
1453 if ( m >= t || *m != -SNUMBER ) break;
1454 }
1455 if ( ( i == ABS(T->numind) ) &&
1456 ( ( isp = FindTableTree(T,tstart+FUNHEAD+1,2) ) >= 0 ) ) {
1457 if ( ( T->tablepointers[isp+ABS(T->numind)+4] & ELEMENTLOADED ) == 0 ) {
1458 T->tablepointers[isp+ABS(T->numind)+4] |= ELEMENTUSED;
1459 }
1460 }
1461 else {
1462 MesPrint("TestUse: Encountered a table element inside tbl_ that does not correspond to a tablebase element");
1463 error = -1;
1464 }
1465 }
1466 return(error);
1467}
1468
1469/*
1470 #] TestUse :
1471 #[ CoTBaudit :
1472*/
1473
1474int CoTBaudit(UBYTE *s)
1475{
1476 DBASE *d;
1477 UBYTE *name, *tail;
1478 int i, j, error = 0, num;
1479
1480 if ( ( d = FindTB(tablebasename) ) == 0 ) {
1481 MesPrint("&No open tablebase with the name %s",tablebasename);
1482 return(-1);
1483 }
1484 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
1485 while ( *s ) {
1486/*
1487 Get the options here
1488 They will mainly involve the sorting of the output.
1489*/
1490 s++;
1491 }
1492 s = (UBYTE *)(d->tablenames); num = 0;
1493 while ( *s ) {
1494 num++;
1495 name = s; while ( *s ) s++; s++;
1496 tail = s; while ( *s ) s++; s++;
1497 MesPrint("Table,sparse,%s%s)",name,tail);
1498 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1499 for ( j = 0; j < NUMOBJECTS; j++ ) {
1500 if ( d->iblocks[i]->objects[j].tablenumber == num ) {
1501 MesPrint(" %s(%s)",name,d->iblocks[i]->objects[j].element);
1502 }
1503 }
1504 }
1505 }
1506 return(error);
1507}
1508
1509/*
1510 #] CoTBaudit :
1511 #[ CoTBon :
1512*/
1513
1514int CoTBon(UBYTE *s)
1515{
1516 DBASE *d;
1517 UBYTE *ss, c;
1518 int error = 0;
1519 if ( ( d = FindTB(tablebasename) ) == 0 ) {
1520 MesPrint("&No open tablebase with the name %s",tablebasename);
1521 return(-1);
1522 }
1523 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
1524 while ( *s ) {
1525 ss = SkipAName(s);
1526 c = *ss; *ss = 0;
1527 if ( StrICmp(s,(UBYTE *)("compress")) == 0 ) {
1528 d->mode &= ~NOCOMPRESS;
1529 }
1530 else {
1531 MesPrint("&subkey %s not defined in TableBase On statement");
1532 error = 1;
1533 }
1534 *ss = c; s = ss;
1535 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
1536 }
1537 return(error);
1538}
1539
1540/*
1541 #] CoTBon :
1542 #[ CoTBoff :
1543*/
1544
1545int CoTBoff(UBYTE *s)
1546{
1547 DBASE *d;
1548 UBYTE *ss, c;
1549 int error = 0;
1550 if ( ( d = FindTB(tablebasename) ) == 0 ) {
1551 MesPrint("&No open tablebase with the name %s",tablebasename);
1552 return(-1);
1553 }
1554 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
1555 while ( *s ) {
1556 ss = SkipAName(s);
1557 c = *ss; *ss = 0;
1558 if ( StrICmp(s,(UBYTE *)("compress")) == 0 ) {
1559 d->mode |= NOCOMPRESS;
1560 }
1561 else {
1562 MesPrint("&subkey %s not defined in TableBase Off statement");
1563 error = 1;
1564 }
1565 *ss = c; s = ss;
1566 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
1567 }
1568 return(error);
1569}
1570
1571/*
1572 #] CoTBoff :
1573 #[ CoTBcleanup :
1574*/
1575
1576int CoTBcleanup(UBYTE *s)
1577{
1578 DUMMYUSE(s);
1579 MesPrint("&TableBase Cleanup statement not yet implemented");
1580 return(1);
1581}
1582
1583/*
1584 #] CoTBcleanup :
1585 #[ CoTBreplace :
1586*/
1587
1588int CoTBreplace(UBYTE *s)
1589{
1590 DUMMYUSE(s);
1591 MesPrint("&TableBase Replace statement not yet implemented");
1592 return(1);
1593}
1594
1595/*
1596 #] CoTBreplace :
1597 #[ CoTBuse :
1598
1599 Here the actual table use as determined in TestUse causes the needed
1600 table elements to be loaded
1601*/
1602
1603int CoTBuse(UBYTE *s)
1604{
1605 GETIDENTITY
1606 DBASE *d;
1607 MLONG basenumber;
1608 UBYTE *arguments, *rhs, *buffer, *t, *u, c, *tablename, *p;
1609 LONG size, sum, x;
1610 int i, j, error = 0, error1 = 0, k;
1611 TABLES T = 0;
1612 WORD type, funnum, mode, *w;
1613 if ( ( d = FindTB(tablebasename) ) == 0 ) {
1614 MesPrint("&No open tablebase with the name %s",tablebasename);
1615 return(-1);
1616 }
1617 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
1618 if ( *s ) {
1619 while ( *s ) {
1620 tablename = s;
1621 if ( ( s = SkipAName(s) ) == 0 ) return(1);
1622 c = *s; *s = 0;
1623 if ( ( GetVar(tablename,&type,&funnum,CFUNCTION,NOAUTO) == NAMENOTFOUND )
1624 || ( T = functions[funnum].tabl ) == 0 ) {
1625 MesPrint("&%s should be a previously declared table",tablename);
1626 basenumber = 0;
1627 }
1628 else if ( T->sparse == 0 ) {
1629 MesPrint("&%s should be a sparse table",tablename);
1630 basenumber = 0;
1631 }
1632 else { basenumber = GetTableName(d,(char *)tablename); }
1633/* if ( T->spare == 0 ) { SpareTable(T); } */
1634 if ( basenumber > 0 ) {
1635 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1636 for ( j = 0; j < NUMOBJECTS; j++ ) {
1637 if ( d->iblocks[i]->objects[j].tablenumber != basenumber ) continue;
1638 arguments = p = (UBYTE *)(d->iblocks[i]->objects[j].element);
1639/*
1640 Now translate the arguments and see whether we need
1641 this one....
1642*/
1643 for ( k = 0, w = AT.WorkPointer; k < ABS(T->numind); k++ ) {
1644 ParseSignedNumber(x,p);
1645 *w++ = x; p++;
1646 }
1647 sum = FindTableTree(T,AT.WorkPointer,1);
1648 if ( sum < 0 ) {
1649 MesPrint("Table %s in tablebase %s has not been loaded properly"
1650 ,tablename,tablebasename);
1651 error = 1;
1652 continue;
1653 }
1654 sum += ABS(T->numind) + 4;
1655 mode = T->tablepointers[sum];
1656 if ( ( mode & ELEMENTLOADED ) == ELEMENTLOADED ) {
1657 T->tablepointers[sum] &= ~ELEMENTUSED;
1658 continue;
1659 }
1660 if ( ( mode & ELEMENTUSED ) == 0 ) continue;
1661/*
1662 We need this one!
1663*/
1664 rhs = (UBYTE *)ReadijObject(d,i,j,(char *)arguments);
1665 if ( rhs ) {
1666 u = rhs; while ( *u ) u++;
1667 size = u-rhs;
1668 u = arguments; while ( *u ) u++;
1669 size += u-arguments;
1670 u = tablename; while ( *u ) u++;
1671 size += u-tablename;
1672 size += 6;
1673 buffer = (UBYTE *)Malloc1(size,"TableBase copy");
1674 t = tablename; u = buffer;
1675 while ( *t ) *u++ = *t++;
1676 *u++ = '(';
1677 t = arguments;
1678 while ( *t ) *u++ = *t++;
1679 *u++ = ')'; *u++ = '=';
1680 t = rhs;
1681 while ( *t ) *u++ = *t++;
1682 if ( t == rhs ) { *u++ = '0'; }
1683 *u++ = 0; *u = 0;
1684 M_free(rhs,"rhs in TBuse xxx");
1685
1686 error1 = CoFill(buffer);
1687
1688 if ( error1 < 0 ) { return(error); }
1689 if ( error1 != 0 ) error = error1;
1690 M_free(buffer,"TableBase copy");
1691 }
1692 T->tablepointers[sum] &= ~ELEMENTUSED;
1693 T->tablepointers[sum] |= ELEMENTLOADED;
1694 }
1695 }
1696 }
1697 *s = c;
1698 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
1699 }
1700 }
1701 else {
1702 s = (UBYTE *)(d->tablenames); basenumber = 0;
1703 while ( *s ) {
1704 basenumber++;
1705 tablename = s;
1706 while ( *s ) s++;
1707 s++;
1708 while ( *s ) s++;
1709 s++;
1710 if ( ( GetVar(tablename,&type,&funnum,CFUNCTION,NOAUTO) == NAMENOTFOUND )
1711 || ( T = functions[funnum].tabl ) == 0 ) {
1712 MesPrint("&%s should be a previously declared table",tablename);
1713 }
1714 else if ( T->sparse == 0 ) {
1715 MesPrint("&%s should be a sparse table",tablename);
1716 }
1717 if ( T->spare && T->mode == 0 ) {
1718 MesPrint("In table %s we have a problem with stubb orders in CoTBuse",tablename);
1719 error = -1;
1720 }
1721/* if ( T->spare == 0 ) { SpareTable(T); } */
1722 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1723 for ( j = 0; j < NUMOBJECTS; j++ ) {
1724 if ( d->iblocks[i]->objects[j].tablenumber == basenumber ) {
1725 arguments = p = (UBYTE *)(d->iblocks[i]->objects[j].element);
1726/*
1727 Now translate the arguments and see whether we need
1728 this one....
1729*/
1730 for ( k = 0, w = AT.WorkPointer; k < ABS(T->numind); k++ ) {
1731 ParseSignedNumber(x,p);
1732 *w++ = x; p++;
1733 }
1734 sum = FindTableTree(T,AT.WorkPointer,1);
1735 if ( sum < 0 ) {
1736 MesPrint("Table %s in tablebase %s has not been loaded properly"
1737 ,tablename,tablebasename);
1738 error = 1;
1739 continue;
1740 }
1741 sum += ABS(T->numind) + 4;
1742 mode = T->tablepointers[sum];
1743 if ( ( mode & ELEMENTLOADED ) == ELEMENTLOADED ) {
1744 T->tablepointers[sum] &= ~ELEMENTUSED;
1745 continue;
1746 }
1747 if ( ( mode & ELEMENTUSED ) == 0 ) continue;
1748/*
1749 We need this one!
1750*/
1751 rhs = (UBYTE *)ReadijObject(d,i,j,(char *)arguments);
1752 if ( rhs ) {
1753 u = rhs; while ( *u ) u++;
1754 size = u-rhs;
1755 u = arguments; while ( *u ) u++;
1756 size += u-arguments;
1757 u = tablename; while ( *u ) u++;
1758 size += u-tablename;
1759 size += 6;
1760 buffer = (UBYTE *)Malloc1(size,"TableBase copy");
1761 t = tablename; u = buffer;
1762 while ( *t ) *u++ = *t++;
1763 *u++ = '(';
1764 t = arguments;
1765 while ( *t ) *u++ = *t++;
1766 *u++ = ')'; *u++ = '=';
1767
1768 t = rhs;
1769 while ( *t ) *u++ = *t++;
1770 if ( t == rhs ) { *u++ = '0'; }
1771 *u++ = 0; *u = 0;
1772 M_free(rhs,"rhs in TBuse");
1773
1774 error1 = CoFill(buffer);
1775
1776 if ( error1 < 0 ) { return(error); }
1777 if ( error1 != 0 ) error = error1;
1778 M_free(buffer,"TableBase copy");
1779 }
1780 T->tablepointers[sum] &= ~ELEMENTUSED;
1781 T->tablepointers[sum] |= ELEMENTLOADED;
1782 }
1783 }
1784 }
1785 }
1786 }
1787 return(error);
1788}
1789
1790/*
1791 #] CoTBuse :
1792 #[ CoApply :
1793
1794 Possibly to be followed by names of tables.
1795*/
1796
1797int CoApply(UBYTE *s)
1798{
1799 GETIDENTITY
1800 UBYTE *tablename, c;
1801 WORD type, funnum, *w;
1802 TABLES T;
1803 LONG maxtogo = MAXPOSITIVE;
1804 int error = 0;
1805 w = AT.WorkPointer;
1806 if ( FG.cTable[*s] == 1 ) {
1807 maxtogo = 0;
1808 while ( FG.cTable[*s] == 1 ) {
1809 maxtogo = maxtogo*10 + (*s-'0');
1810 s++;
1811 }
1812 while ( *s == ',' ) s++;
1813 if ( maxtogo > MAXPOSITIVE || maxtogo < 0 ) maxtogo = MAXPOSITIVE;
1814 }
1815 *w++ = TYPEAPPLY; *w++ = 3; *w++ = maxtogo;
1816 while ( *s ) {
1817 tablename = s;
1818 if ( ( s = SkipAName(s) ) == 0 ) return(1);
1819 c = *s; *s = 0;
1820 if ( ( GetVar(tablename,&type,&funnum,CFUNCTION,NOAUTO) == NAMENOTFOUND )
1821 || ( T = functions[funnum].tabl ) == 0 ) {
1822 MesPrint("&%s should be a previously declared table",tablename);
1823 error = 1;
1824 }
1825 else if ( T->sparse == 0 ) {
1826 MesPrint("&%s should be a sparse table",tablename);
1827 error = 1;
1828 }
1829 *w++ = funnum + FUNCTION;
1830 *s = c;
1831 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1832 }
1833 AT.WorkPointer[1] = w - AT.WorkPointer;
1834/*
1835 if ( AT.WorkPointer[1] > 2 ) {
1836 AddNtoL(AT.WorkPointer[1],AT.WorkPointer);
1837 }
1838*/
1839 AddNtoL(AT.WorkPointer[1],AT.WorkPointer);
1840/*
1841 AT.WorkPointer[0] = TYPEAPPLYRESET;
1842 AddNtoL(AT.WorkPointer[1],AT.WorkPointer);
1843*/
1844 return(error);
1845}
1846
1847/*
1848 #] CoApply :
1849 #[ CoTBhelp :
1850*/
1851
1852char *helptb[] = {
1853 "The TableBase statement is used as follows:"
1854 ,"TableBase \"file.tbl\" keyword subkey(s)"
1855 ," in which we have"
1856 ,"Keyword Subkey(s) Action"
1857 ,"open Opens file.tbl for R/W"
1858 ,"create Creates file.tbl for R/W. Old contents are lost"
1859 ,"load Loads all stubs of all tables"
1860 ,"load tablename(s) Loads all stubs the tables mentioned"
1861 ,"enter Loads all stubs and rhs of all tables"
1862 ,"enter tablename(s) Loads all stubs and rhs of the tables mentioned"
1863 ,"audit Prints list of contents"
1864/* ,"replace tablename saves a table (with overwrite)" */
1865/* ,"replace tableelement saves a table element (with overwrite)" */
1866/* ,"cleanup makes tables contingent" */
1867 ,"addto tablename adds all elements if not yet there"
1868 ,"addto tableelement adds element if not yet there"
1869/* ,"delete tablename removes table from tablebase" */
1870/* ,"delete tableelement removes element from tablebase" */
1871 ,"on compress elements are stored in gzip format (default)"
1872 ,"off compress elements are stored in uncompressed format"
1873 ,"use compiles all needed elements"
1874 ,"use tablename(s) compiles all needed elements of these tables"
1875 ,""
1876 ,"Related commands are:"
1877 ,"testuse marks which tbl_ elements occur for all tables"
1878 ,"testuse tablename(s) marks which tbl_ elements occur for given tables"
1879 ,"apply replaces tbl_ if rhs available"
1880 ,"apply tablename(s) replaces tbl_ for given tables if rhs available"
1881 ,""
1882 };
1883
1884int CoTBhelp(UBYTE *s)
1885{
1886 int i, ii = sizeof(helptb)/sizeof(char *);
1887 DUMMYUSE(s);
1888 for ( i = 0; i < ii; i++ ) MesPrint("%s",helptb[i]);
1889 return(0);
1890}
1891
1892/*
1893 #] CoTBhelp :
1894 #[ ReWorkT :
1895
1896 Replaces the STUBBS of the functions in the list.
1897 This gains one space. Hence we have to be very careful
1898*/
1899
1900void ReWorkT(WORD *term, WORD *funs, WORD numfuns)
1901{
1902 WORD *tstop, *tend, *m, *t, *tt, *mm, *mmm, *r, *rr;
1903 int i, j;
1904 tend = term + *term; tstop = tend - ABS(tend[-1]);
1905 m = t = term+1;
1906 while ( t < tstop ) {
1907 if ( *t == TABLESTUB ) {
1908 for ( i = 0; i < numfuns; i++ ) {
1909 if ( -t[FUNHEAD] == funs[i] ) break;
1910 }
1911 if ( numfuns == 0 || i < numfuns ) { /* Hit */
1912 i = t[1] - 1;
1913 *m++ = -t[FUNHEAD]; *m++ = i; t += 2; i -= FUNHEAD;
1914 if ( m < t ) { for ( j = 0; j < FUNHEAD-2; j++ ) *m++ = *t++; }
1915 else { m += FUNHEAD-2; t += FUNHEAD-2; }
1916 t++;
1917 while ( i-- > 0 ) { *m++ = *t++; }
1918 tt = t; mm = m;
1919 if ( mm < tt ) {
1920 while ( tt < tend ) *mm++ = *tt++;
1921 *term = mm - term;
1922 tend = term + *term; tstop = tend - ABS(tend[-1]);
1923 t = m;
1924 }
1925 }
1926 else { goto inc; }
1927 }
1928 else if ( *t >= FUNCTION ) {
1929 tt = t + t[1];
1930 mm = m;
1931 for ( j = 0; j < FUNHEAD; j++ ) {
1932 if ( m == t ) { m++; t++; }
1933 else *m++ = *t++;
1934 }
1935 while ( t < tt ) {
1936 if ( *t <= -FUNCTION ) {
1937 if ( m == t ) { m++; t++; }
1938 else *m++ = *t++;
1939 }
1940 else if ( *t < 0 ) {
1941 if ( m == t ) { m += 2; t += 2; }
1942 else { *m++ = *t++; *m++ = *t++; }
1943 }
1944 else {
1945 rr = t + *t; mmm = m;
1946 for ( j = 0; j < ARGHEAD; j++ ) {
1947 if ( m == t ) { m++; t++; }
1948 else *m++ = *t++;
1949 }
1950 while ( t < rr ) {
1951 r = t + *t;
1952 ReWorkT(t,funs,numfuns);
1953 j = *t;
1954 if ( m == t ) { m += j; t += j; }
1955 else { while ( j-- >= 0 ) *m++ = *t++; }
1956 t = r;
1957 }
1958 *mmm = m-mmm;
1959 }
1960 }
1961 mm[1] = m - mm;
1962 t = tt;
1963 }
1964 else {
1965inc: j = t[1];
1966 if ( m < t ) { while ( j-- >= 0 ) *m++ = *t++; }
1967 else { m += j; t += j; }
1968 }
1969 }
1970 if ( m < t ) {
1971 while ( t < tend ) *m++ = *t++;
1972 *term = m - term;
1973 }
1974}
1975
1976/*
1977 #] ReWorkT :
1978 #[ Apply :
1979*/
1980
1981void Apply(WORD *term, WORD level)
1982{
1983 WORD *funs, numfuns;
1984 TABLES T;
1985 int i, j;
1986 CBUF *C = cbuf+AM.rbufnum;
1987/*
1988 Point the tables in the proper direction
1989*/
1990 numfuns = C->lhs[level][1] - 2;
1991 funs = C->lhs[level] + 2;
1992 if ( numfuns > 0 ) {
1993 for ( i = MAXBUILTINFUNCTION-FUNCTION; i < AC.FunctionList.num; i++ ) {
1994 if ( ( T = functions[i].tabl ) != 0 ) {
1995 for ( j = 0; j < numfuns; j++ ) {
1996 if ( i == (funs[j]-FUNCTION) && T->spare ) {
1997 FlipTable(&(functions[i]),0);
1998 break;
1999 }
2000 }
2001 }
2002 }
2003 }
2004 else {
2005 for ( i = MAXBUILTINFUNCTION-FUNCTION; i < AC.FunctionList.num; i++ ) {
2006 if ( ( T = functions[i].tabl ) != 0 ) {
2007 if ( T->spare ) FlipTable(&(functions[i]),0);
2008 }
2009 }
2010 }
2011/*
2012 Now the replacements everywhere of
2013 id tbl_(table,?a) = table(?a);
2014 Actually, this has to be done recursively.
2015 Note that we actually gain one space.
2016*/
2017 ReWorkT(term,funs,numfuns);
2018}
2019
2020/*
2021 #] Apply :
2022 #[ ApplyExec :
2023
2024 Replaces occurrences of tbl_(table,indices,pattern) by the proper
2025 rhs of table(indices,pattern). It does this up to maxtogo times
2026 in the given term. It starts with the occurrences inside the
2027 arguments of functions. If necessary it finishes at groundlevel.
2028 An infinite number of tries is indicated by maxtogo = 2^15-1 or 2^31-1.
2029 The occurrences are replaced by subexpressions. This allows TestSub
2030 to finish the job properly.
2031
2032 The main trick here is T = T->spare which turns to the proper rhs.
2033
2034 The return value is the number of substitutions that can still be made
2035 based on maxtogo. Hence, if the returnvalue is different from maxtogo
2036 there was a substitution.
2037*/
2038
2039int ApplyExec(WORD *term, int maxtogo, WORD level)
2040{
2041 GETIDENTITY
2042 WORD rhsnumber, *Tpattern, *funs, numfuns, funnum;
2043 WORD ii, *t, *t1, *w, *p, *m, *m1, *u, *r, tbufnum, csize, wilds;
2044 NESTING NN;
2045 int i, j, isp, stilltogo;
2046 CBUF *C;
2047 TABLES T;
2048/*
2049 Startup. We need NestPoin for when we have to replace something deep down.
2050*/
2051 t = term;
2052 m = t + *t;
2053 csize = ABS(m[-1]);
2054 m -= csize;
2055 AT.NestPoin->termsize = t;
2056 if ( AT.NestPoin == AT.Nest ) AN.EndNest = t + *t;
2057 t++;
2058/*
2059 First we look inside function arguments. Also when clean!
2060*/
2061 while ( t < m ) {
2062 if ( *t < FUNCTION ) { t += t[1]; continue; }
2063 if ( functions[*t-FUNCTION].spec > 0 ) { t += t[1]; continue; }
2064 AT.NestPoin->funsize = t;
2065 r = t + t[1];
2066 t += FUNHEAD;
2067 while ( t < r ) {
2068 if ( *t < 0 ) { NEXTARG(t); continue; }
2069 AT.NestPoin->argsize = t1 = t;
2070 u = t + *t;
2071 t += ARGHEAD;
2072 AT.NestPoin++;
2073 while ( t < u ) {
2074/*
2075 Now we loop over the terms inside a function argument
2076 This defines a recursion and we have to call ApplyExec again.
2077 The real problem is when we catch something and we have
2078 to insert a subexpression pointer. This may use more or
2079 less space and the whole term has to be readjusted.
2080 This is why we have the NestPoin variables. They tell us
2081 where the sizes of the term, the function and the arguments
2082 are sitting, and also where the dirty flags are.
2083 This readjusting is of course done in the groundlevel code.
2084 Here we worry abound the maxtogo count.
2085*/
2086 stilltogo = ApplyExec(t,maxtogo,level);
2087 if ( stilltogo != maxtogo ) {
2088 if ( stilltogo <= 0 ) {
2089 AT.NestPoin--;
2090 return(stilltogo);
2091 }
2092 maxtogo = stilltogo;
2093 u = t1 + *t1;
2094 m = term + *term - csize;
2095 }
2096 t += *t;
2097 }
2098 AT.NestPoin--;
2099 }
2100 }
2101/*
2102 Now we look at the ground level
2103*/
2104 C = cbuf+AM.rbufnum;
2105 t = term + 1;
2106 while ( t < m ) {
2107 if ( *t != TABLESTUB ) { t += t[1]; continue; }
2108 funnum = -t[FUNHEAD];
2109 if ( ( funnum < FUNCTION )
2110 || ( funnum >= FUNCTION+WILDOFFSET )
2111 || ( ( T = functions[funnum-FUNCTION].tabl ) == 0 )
2112 || ( T->sparse == 0 )
2113 || ( T->spare == 0 ) ) { t += t[1]; continue; }
2114 numfuns = C->lhs[level][1] - 3;
2115 funs = C->lhs[level] + 3;
2116 if ( numfuns > 0 ) {
2117 for ( i = 0; i < numfuns; i++ ) {
2118 if ( funs[i] == funnum ) break;
2119 }
2120 if ( i >= numfuns ) { t += t[1]; continue; }
2121 }
2122 r = t + t[1];
2123 AT.NestPoin->funsize = t + 1;
2124 t1 = t;
2125 t += FUNHEAD + 1;
2126/*
2127 Test whether the table catches
2128 Test 1: index arguments and range. isp will be the number
2129 of the element in the table.
2130*/
2131 T = T->spare;
2132#ifdef WITHPTHREADS
2133 Tpattern = T->pattern[identity];
2134#else
2135 Tpattern = T->pattern;
2136#endif
2137 p = Tpattern+FUNHEAD+1;
2138 for ( i = 0; i < ABS(T->numind); i++, t += 2 ) {
2139 if ( *t != -SNUMBER ) break;
2140 }
2141 if ( i < ABS(T->numind) ) { t = r; continue; }
2142 isp = FindTableTree(T,t1+FUNHEAD+1,2);
2143 if ( isp < 0 ) { t = r; continue; }
2144 rhsnumber = T->tablepointers[isp+ABS(T->numind)];
2145#if ( TABLEEXTENSION == 2 )
2146 tbufnum = T->bufnum;
2147#else
2148 tbufnum = T->tablepointers[isp+ABS(T->numind)+1];
2149#endif
2150 t = t1+FUNHEAD+2;
2151 ii = ABS(T->numind);
2152 while ( --ii >= 0 ) {
2153 *p = *t; t += 2; p += 2;
2154 }
2155/*
2156 If there are more arguments we have to do some
2157 pattern matching. This should be easy. We adapted the
2158 pattern, so that the array indices match already.
2159*/
2160#ifdef WITHPTHREADS
2161 AN.FullProto = T->prototype[identity];
2162#else
2163 AN.FullProto = T->prototype;
2164#endif
2165 AN.WildValue = AN.FullProto + SUBEXPSIZE;
2166 AN.WildStop = AN.FullProto+AN.FullProto[1];
2167 ClearWild(BHEAD0);
2168 AN.RepFunNum = 0;
2169 AN.RepFunList = AN.EndNest;
2170 AT.WorkPointer = (WORD *)(((UBYTE *)(AN.EndNest)) + AM.MaxTer/2);
2171/*
2172 The RepFunList is after the term but not very relevant.
2173 We need because MatchFunction uses it
2174*/
2175 if ( AT.WorkPointer + t1[1] >= AT.WorkTop ) { MesWork(); }
2176 wilds = 0;
2177 w = AT.WorkPointer;
2178 *w++ = -t1[FUNHEAD];
2179 *w++ = t1[1] - 1;
2180 for ( i = 2; i < FUNHEAD; i++ ) *w++ = t1[i];
2181 t = t1 + FUNHEAD+1;
2182 while ( t < r ) *w++ = *t++;
2183 t = AT.WorkPointer;
2184 AT.WorkPointer = w;
2185 if ( MatchFunction(BHEAD Tpattern,t,&wilds) > 0 ) {
2186/*
2187 Here we caught one. Now we should worry about:
2188 1: inserting the subexpression pointer with its wildcards
2189 2: NestPoin because we may not be at the lowest level
2190 The function starts at t1.
2191*/
2192#ifdef WITHPTHREADS
2193 m1 = T->prototype[identity];
2194#else
2195 m1 = T->prototype;
2196#endif
2197 m1[2] = rhsnumber;
2198 m1[4] = tbufnum;
2199 t = t1;
2200 j = t[1];
2201 i = m1[1];
2202 if ( j > i ) {
2203 j = i - j;
2204 NCOPY(t,m1,i);
2205 m1 = AN.EndNest;
2206 while ( r < m1 ) *t++ = *r++;
2207 AN.EndNest = t;
2208 *term += j;
2209 NN = AT.NestPoin;
2210 while ( NN > AT.Nest ) {
2211 NN--;
2212 NN->termsize[0] += j;
2213 NN->funsize[1] += j;
2214 NN->argsize[0] += j;
2215 NN->funsize[2] |= DIRTYFLAG;
2216 NN->argsize[1] |= DIRTYFLAG;
2217 }
2218 m += j;
2219 }
2220 else if ( j < i ) {
2221 j = i-j;
2222 t = AN.EndNest;
2223 while ( t >= r ) { t[j] = *t; t--; }
2224 t = t1;
2225 NCOPY(t,m1,i);
2226 AN.EndNest += j;
2227 *term += j;
2228 NN = AT.NestPoin;
2229 while ( NN > AT.Nest ) {
2230 NN--;
2231 NN->termsize[0] += j;
2232 NN->funsize[1] += j;
2233 NN->argsize[0] += j;
2234 NN->funsize[2] |= DIRTYFLAG;
2235 NN->argsize[1] |= DIRTYFLAG;
2236 }
2237 m += j;
2238 }
2239 else {
2240 NCOPY(t,m1,j);
2241 }
2242 r = t1 + t1[1];
2243 maxtogo--;
2244 if ( maxtogo <= 0 ) return(maxtogo);
2245 }
2246 t = r;
2247 }
2248 return(maxtogo);
2249}
2250
2251/*
2252 #] ApplyExec :
2253 #[ ApplyReset :
2254*/
2255
2256void ApplyReset(WORD level)
2257{
2258 WORD *funs, numfuns;
2259 TABLES T;
2260 int i, j;
2261 CBUF *C = cbuf+AM.rbufnum;
2262
2263 numfuns = C->lhs[level][1] - 2;
2264 funs = C->lhs[level] + 2;
2265 if ( numfuns > 0 ) {
2266 for ( i = MAXBUILTINFUNCTION-FUNCTION; i < AC.FunctionList.num; i++ ) {
2267 if ( ( T = functions[i].tabl ) != 0 ) {
2268 for ( j = 0; j < numfuns; j++ ) {
2269 if ( i == (funs[j]-FUNCTION) && T->spare ) {
2270 FlipTable(&(functions[i]),1);
2271 break;
2272 }
2273 }
2274 }
2275 }
2276 }
2277 else {
2278 for ( i = MAXBUILTINFUNCTION-FUNCTION; i < AC.FunctionList.num; i++ ) {
2279 if ( ( T = functions[i].tabl ) != 0 ) {
2280 if ( T->spare ) FlipTable(&(functions[i]),1);
2281 }
2282 }
2283 }
2284}
2285
2286/*
2287 #] ApplyReset :
2288 #[ TableReset :
2289*/
2290
2291void TableReset(void)
2292{
2293 TABLES T;
2294 int i;
2295
2296 for ( i = MAXBUILTINFUNCTION-FUNCTION; i < AC.FunctionList.num; i++ ) {
2297 if ( ( T = functions[i].tabl ) != 0 && T->spare && T->mode == 0 ) {
2298 functions[i].tabl = T->spare;
2299 }
2300 }
2301}
2302
2303/*
2304 #] TableReset :
2305 #[ LoadTableElement :
2306?????
2307int LoadTableElement(DBASE *d, TABLE *T, WORD num)
2308{
2309}
2310
2311 #] LoadTableElement :
2312 #[ ReleaseTB :
2313
2314 Releases all TableBases
2315*/
2316
2317int ReleaseTB(void)
2318{
2319 DBASE *d;
2320 int i;
2321 for ( i = NumTableBases - 1; i >= 0; i-- ) {
2322 d = tablebases+i;
2323 fclose(d->handle);
2324 FreeTableBase(d);
2325 }
2326 return(0);
2327}
2328
2329/*
2330 #] ReleaseTB :
2331*/
UBYTE * SkipAName(UBYTE *s)
Definition compiler.c:443
int AddNtoL(int n, WORD *array)
Definition comtool.c:288
int inicbufs(void)
Definition comtool.c:47
int Generator(PHEAD WORD *, WORD)
Definition proces.c:3249
WORD ** lhs
Definition structs.h:974
TABLES tabl
Definition structs.h:488
WORD mini
Definition structs.h:302
WORD size
Definition structs.h:304
WORD * pattern
Definition structs.h:349
WORD * buffers
Definition structs.h:357
struct TaBlEs * spare
Definition structs.h:356
WORD * tablepointers
Definition structs.h:343
UBYTE * argtail
Definition structs.h:354
int numtree
Definition structs.h:367
COMPTREE * boomlijst
Definition structs.h:353
LONG reserved
Definition structs.h:359
WORD buffersfill
Definition structs.h:372
int MaxTreeSize
Definition structs.h:369
int strict
Definition structs.h:365
WORD bufferssize
Definition structs.h:371
WORD * flags
Definition structs.h:352
WORD * prototype
Definition structs.h:348
WORD mode
Definition structs.h:374
LONG mdefined
Definition structs.h:361
MINMAX * mm
Definition structs.h:351
int rootnum
Definition structs.h:368
WORD bufnum
Definition structs.h:370
int bounds
Definition structs.h:364
int numind
Definition structs.h:363
LONG totind
Definition structs.h:358
int sparse
Definition structs.h:366
LONG defined
Definition structs.h:360
WORD tablenum
Definition structs.h:373
Definition minos.h:123
struct TaBlEs * TABLES
int blnce
Definition structs.h:293
int right
Definition structs.h:291
int parent
Definition structs.h:289
int value
Definition structs.h:292
int left
Definition structs.h:290
int usage
Definition structs.h:294