Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

563551 views
1
2
/**************************************************************************
3
4
parser.c
5
Colin Ramsay ([email protected])
6
2 Mar 01
7
8
ADVANCED COSET ENUMERATOR, Version 3.001
9
10
Copyright 2000
11
Centre for Discrete Mathematics and Computing,
12
Department of Mathematics and
13
Department of Computer Science & Electrical Engineering,
14
The University of Queensland, QLD 4072.
15
(http://staff.itee.uq.edu.au/havas)
16
17
Parser and dispatcher code for stand-alone ACE. We try to ensure that we
18
only change things in response to a command if the entire command is ok.
19
This means that the state is always consistent, and we can usually just
20
continue.
21
22
Note: the al2_continue() routine is intended for cases where an `error'
23
does not effect the ability to continue, while al2_restart() is intended
24
for errors which (may) mean that continuing is not possible, so we have to
25
(re)start an enumeration. I'm not sure that I'm always careful in calling
26
the `right' one; we may have to tinker with this in the light of
27
experience.
28
29
**************************************************************************/
30
31
#include "al2.h"
32
33
#include <ctype.h>
34
#include <string.h>
35
36
int al2_pwrd(int); /* Forward declaration (parser is recursive) */
37
38
/******************************************************************
39
void al2_readkey(void)
40
41
Read a keyword into currkey[], converting it to LC. This removes
42
all leading WS, compresses middle WS to single ' ', and removes
43
trailing WS. It checks for bad characters and too short/long key,
44
and advances position to argument (if necessary). Note that
45
currkey has 64 posns (0..63), and we have to reserve one for the
46
string terminating '\0' character.
47
******************************************************************/
48
49
void al2_readkey(void)
50
{
51
int i = 0;
52
53
/* Copy the keyword into currkey[] */
54
while ( currip != ':' && currip != ';' && currip != '\n'
55
&& currip != '\r' && currip != EOF )
56
{
57
if (islower(currip))
58
{
59
if (i > 62)
60
{ al2_continue("keyword too long"); }
61
currkey[i++] = currip;
62
}
63
else if (isupper(currip))
64
{
65
if (i > 62)
66
{ al2_continue("keyword too long"); }
67
currkey[i++] = tolower(currip);
68
}
69
else if (currip == ' ' || currip == '\t')
70
{
71
if (i > 0 && currkey[i-1] != ' ') /* leading/multiple spaces? */
72
{
73
if (i > 63) /* may be removable trailing space */
74
{ al2_continue("keyword too long"); }
75
currkey[i++] = ' ';
76
}
77
}
78
else
79
{ al2_continue("keywords must only contain letters"); }
80
al2_nextip();
81
}
82
83
if (i > 0 && currkey[i-1] == ' ') /* remove trailing space */
84
{ i--; }
85
currkey[i] = '\0'; /* string terminator */
86
87
if (i == 0)
88
{ al2_continue("empty keyword"); }
89
90
if (currip == ':') /* skip any following ':' & WS */
91
{ al2_nextnw(); }
92
}
93
94
/******************************************************************
95
void al2_readname(void)
96
97
Read a `name' (ie, command argument). Used for group/subgroup
98
names/descriptions, I/O filenames, and system calls. There is only
99
one of these (a fixed length <128 global), so we may need to take a
100
copy if it'll be required later. Note that currip has been setup
101
to point to a non-blank char (ie, either the first char of the
102
string or an end-of-command char). Note that we strip trailing
103
spaces & tabs from the name, for `neatness'. We assume ASCII.
104
******************************************************************/
105
106
void al2_readname(void)
107
{
108
int i = 0;
109
110
while ( currip != ';' && currip != '\n' && currip != '\r' &&
111
currip != EOF )
112
{
113
if (!((currip >= ' ' && currip <= '~') || (currip == '\t')))
114
{ al2_continue("string contains invalid character"); }
115
if (i > 126) /* 0..126 is data, 127 is '\0' */
116
{ al2_continue("string too long"); }
117
118
currname[i++] = currip;
119
al2_nextip();
120
}
121
122
while (i > 0 && (currname[i-1] == ' ' || currname[i-1] == '\t'))
123
{ i--; }
124
currname[i] = '\0';
125
}
126
127
/******************************************************************
128
int al2_readmult(void)
129
130
Reads the multiplier for the workspace size, if we recognise it.
131
******************************************************************/
132
133
int al2_readmult(void)
134
{
135
int u = 1; /* Default is x1 */
136
137
if (currip == 'k' || currip == 'K')
138
{
139
u = KILO;
140
al2_nextnw();
141
}
142
else if (currip == 'm' || currip == 'M')
143
{
144
u = MEGA;
145
al2_nextnw();
146
}
147
else if (currip == 'g' || currip == 'G')
148
{
149
u = GIGA;
150
al2_nextnw();
151
}
152
153
return u;
154
}
155
156
/******************************************************************
157
int al2_readgen(void)
158
159
Reads in a (possibly comma separated) list of generator letters.
160
These are stored (in lower case) in the order they're read in the
161
currname array. Duplicates are verboten and the number of
162
generators read is returned. Currip is guaranteed to be a letter,
163
so j > 0 on return is certain (in the absence of errors).
164
******************************************************************/
165
166
int al2_readgen(void)
167
{
168
int i, j = 0;
169
170
while ( currip != ';' && currip != '\n' && currip != '\r' &&
171
currip != EOF )
172
{
173
if (islower(currip))
174
{
175
for (i = 1; i <= j; i++)
176
{
177
if (currname[i] == currip)
178
{ al2_continue("duplicated generator"); }
179
}
180
currname[++j] = currip;
181
}
182
else
183
{ al2_continue("generators are letters between 'a' & 'z'"); }
184
185
al2_nextnw();
186
if (currip == ',')
187
{ al2_nextnw(); }
188
}
189
190
return(j);
191
}
192
193
/******************************************************************
194
Logic al2_match(char *pattern)
195
196
Test whether currkey can be matched to pattern.
197
******************************************************************/
198
199
Logic al2_match(char *pattern)
200
{
201
int i;
202
203
/* first try to match the required part */
204
for (i = 0; pattern[i] != '\0' && pattern[i] != '['; i++)
205
{
206
if (pattern[i] != currkey[i])
207
{ return FALSE; }
208
}
209
210
/* if the rest is optional, try to match it */
211
if (pattern[i] == '[')
212
{
213
for ( ; pattern[i+1] != '\0' && pattern[i+1] != ']'; i++)
214
{
215
if (pattern[i+1] != currkey[i])
216
{ return (currkey[i] == '\0'); }
217
}
218
}
219
220
/* everything matched, but the keyword should not be longer */
221
return (currkey[i] == '\0');
222
}
223
224
/******************************************************************
225
void al2_endcmd(void)
226
227
To terminate a command, we must see a ';' or a newline.
228
******************************************************************/
229
230
void al2_endcmd(void)
231
{
232
if (currip != ';' && currip != '\n' && currip != '\r' && currip != EOF)
233
{ al2_continue("command must be terminated by ';' or <newline>"); }
234
}
235
236
/******************************************************************
237
int al2_readuint(void)
238
239
Read in an unsigned integer
240
******************************************************************/
241
242
int al2_readuint(void)
243
{
244
int u = 0;
245
246
if (isdigit(currip))
247
{
248
while (isdigit(currip))
249
{
250
u = 10*u + (currip - '0');
251
al2_nextip();
252
}
253
al2_skipws();
254
}
255
else
256
{ al2_continue("number must begin with digit"); }
257
258
return(u);
259
}
260
261
/******************************************************************
262
int al2_readint(void)
263
264
Read in a (possibly signed) integer
265
******************************************************************/
266
267
int al2_readint(void)
268
{
269
if (isdigit(currip))
270
{ return(al2_readuint()); }
271
else if (currip == '+')
272
{
273
al2_nextnw();
274
return(al2_readuint());
275
}
276
else if (currip == '-')
277
{
278
al2_nextnw();
279
return(-al2_readuint());
280
}
281
else
282
{ al2_continue("number must begin with digit or '+' or '-'"); }
283
284
return(-1); /* Stops compiler warning; never get here! */
285
}
286
287
/******************************************************************
288
void al2_readia(void)
289
290
Read comma-separated list of <= 32 integers into the integer array.
291
******************************************************************/
292
293
void al2_readia(void)
294
{
295
intcnt = 0;
296
297
if ( !(isdigit(currip) || currip == '+' || currip == '-') )
298
{ return; } /* list is empty */
299
300
intarr[intcnt++] = al2_readint();
301
while (currip == ',')
302
{
303
if (intcnt == 32)
304
{ al2_continue("too many integers in sequence"); }
305
306
al2_nextnw();
307
intarr[intcnt++] = al2_readint();
308
}
309
}
310
311
/**************************************************************************
312
The functions from hereon, until al2_cmdloop(), are responsible for
313
implementing the recursive-descent parser. The current word is built-up in
314
currword, and when this has been done successfully it is added to a temp
315
list of words. If an error occurs, then this list will be `valid'; it will
316
contain all words up to, but not including, the one in error. Currently
317
this list is accessed via a pointer in the `top-level' function _rdwl() or
318
_rdrl(). This pointer should really be made a global, so that we could
319
attempt error-recovery or free up the space it uses (currently, errors may
320
cause memory leakage). A successful call to either of the top-level
321
functions returns a new list, which should be used to replace the current
322
list of either group relators or subgroup generators. It is the caller's
323
(of the parser) responsibility to deallocate any replaced list.
324
**************************************************************************/
325
326
/******************************************************************
327
void al2_addgen(int pos, int gen)
328
329
Add a generator to the current word, growing the word as necessary.
330
******************************************************************/
331
332
void al2_addgen(int pos, int gen)
333
{
334
if (currword == NULL)
335
{
336
currsiz = 16;
337
if ((currword = (int *)malloc(currsiz*sizeof(int))) == NULL)
338
{ al2_continue("out of memory (initial word)"); }
339
}
340
else if (pos >= currsiz) /* valid entries are [0] .. [currsiz-1] */
341
{
342
currsiz *= 2;
343
if ((currword = (int *)realloc(currword, currsiz*sizeof(int))) == NULL)
344
{ al2_continue("out of memory (adding generator)"); }
345
}
346
347
currword[pos] = gen;
348
}
349
350
/******************************************************************
351
void al2_addwrd(int dst, int src, int len)
352
353
Add a word to the current word. Note that this is used to copy
354
from currword to itself, so either dst <= src or dst >= src+len.
355
******************************************************************/
356
357
void al2_addwrd(int dst, int src, int len)
358
{
359
int i;
360
361
for (i = 0; i < len; i++)
362
{ al2_addgen(dst+i, currword[src+i]); }
363
}
364
365
/******************************************************************
366
void al2_invwrd(int pos, int len)
367
368
Sneakily invert a subword of the current word. Note that we have
369
to reverse the order _and_ invert all entries. So we have to touch
370
all posns; hence some of the apparently unnecessary work.
371
******************************************************************/
372
373
void al2_invwrd(int pos, int len)
374
{
375
int i, gen1, gen2;
376
377
for (i = 1; i <= (len+1)/2; i++)
378
{
379
gen1 = currword[pos + i-1];
380
gen2 = currword[pos + len-i];
381
382
currword[pos + i-1] = -gen2;
383
currword[pos + len-i] = -gen1;
384
}
385
}
386
387
/******************************************************************
388
Wlelt *al2_newwrd(int len)
389
390
Make a new word-list element, and copy the first len values from
391
currword into it. Note that currword is indexed from 0, while data
392
in the list is indexed from 1! At this stage all words are fully
393
expanded, and have exponent 1. However, we need to flag those
394
words which were _entered_ as involutions (ie, as x^2, not xx).
395
******************************************************************/
396
397
Wlelt *al2_newwrd(int len)
398
{
399
Wlelt *p;
400
int i;
401
402
if ((p = al1_newelt()) == NULL)
403
{ al2_restart("no memory for new word-list element"); }
404
if ((p->word = (int *)malloc((len+1)*sizeof(int))) == NULL)
405
{ al2_restart("no memory for word-list element data"); }
406
407
for (i = 1; i <= len; i++)
408
{ p->word[i] = currword[i-1]; }
409
p->len = len;
410
p->exp = 1;
411
412
if (len == 2 && currword[0] == currword[1] && currexp == 2)
413
{ p->invol = TRUE; }
414
else
415
{ p->invol = FALSE; }
416
417
return(p);
418
}
419
420
/******************************************************************
421
int al2_pelt(int beg)
422
423
Parses an element into currword, beginning at position beg, and
424
returns the length of the parsed element. The BNF for an element:
425
426
<element> = <generator> ["'"]
427
| "(" <word> { "," <word> } ")" ["'"]
428
| "[" <word> { "," <word> } "]" ["'"]
429
430
Note that (a,b) is parsed as [a,b], but (ab) as ab. Also, [a,b,c]
431
is parsed as [[a,b],c].
432
******************************************************************/
433
434
int al2_pelt(int beg)
435
{
436
int len, len2, gen, sign;
437
char ch;
438
439
if (isalpha(currip)) /* we have 'a'..'z' or 'A'..'Z' */
440
{
441
if (!galpha)
442
{ al2_restart("you specified numeric generators"); }
443
444
if (islower(currip))
445
{
446
ch = currip;
447
sign = 1;
448
}
449
else
450
{
451
ch = tolower(currip);
452
sign = -1;
453
}
454
al2_nextnw();
455
456
gen = genal[ch-'a'+1];
457
if (gen == 0)
458
{ al2_restart("<letter> must be one of the generator letters"); }
459
al2_addgen(beg, sign*gen);
460
len = 1;
461
}
462
else if (isdigit(currip) || currip == '+' || currip == '-')
463
{ /* parse a numeric generator */
464
if (galpha)
465
{ al2_restart("you specified alphabetic generators"); }
466
467
sign = 1;
468
if (currip == '+')
469
{
470
al2_nextnw();
471
if (!isdigit(currip))
472
{ al2_restart("'+' must be followed by generator number"); }
473
}
474
else if (currip == '-')
475
{
476
al2_nextnw();
477
if (!isdigit(currip))
478
{ al2_restart("'-' must be followed by generator number"); }
479
sign = -1;
480
}
481
482
gen = al2_readuint();
483
if (gen == 0 || gen > ndgen)
484
{ al2_restart("<number> must be one of the generator numbers"); }
485
al2_addgen(beg, sign*gen);
486
len = 1;
487
}
488
else if (currip == '(' || currip == '[')
489
{ /* parse parenthesised word / commutator */
490
ch = currip;
491
al2_nextnw();
492
len = al2_pwrd(beg);
493
494
while (currip == ',')
495
{
496
al2_nextnw();
497
len2 = al2_pwrd(beg+len);
498
al2_addwrd(beg+len+len2, beg, len+len2);
499
al2_invwrd(beg, len);
500
al2_invwrd(beg+len, len2);
501
len = 2*(len + len2);
502
}
503
504
if (ch == '(' && currip != ')')
505
{ al2_restart("'(' must have a matching ')'"); }
506
if (ch == '[' && currip != ']')
507
{ al2_restart("'[' must have a matching ']'"); }
508
al2_nextnw();
509
}
510
else /* otherwise this is an error */
511
{
512
al2_restart("<word> must begin with a <generator>, a '(' or a '['");
513
}
514
515
/* A "'" inverts the current element. "''" is not allowed. */
516
517
if (currip == '\'')
518
{
519
al2_invwrd(beg, len);
520
al2_nextnw();
521
}
522
523
return len; /* return the length */
524
}
525
526
/******************************************************************
527
int al2_pfact(int beg)
528
529
Parses a factor into currword, beginning at position beg, and
530
returns the length of the parsed factor. The BNF for a factor:
531
532
<factor> = <element> [ ["^"] <integer> | "^" <element> ]
533
534
Note that if alphabetic generators are used then the exponentiation
535
"^" can be dropped (but not the conjugation "^"), and the exponent
536
"-1" can be abbreviated to "-". So "a^-1 b" can be written as
537
"a^-1b", "a-1b", "a^-b", or "a-b".
538
539
******************************************************************/
540
541
int al2_pfact(int beg)
542
{
543
int len, len2, i;
544
545
len = al2_pelt(beg); /* parse (first) element */
546
547
if ( currip == '^' ||
548
(galpha && (isdigit(currip) || currip == '+' || currip == '-')) )
549
{
550
if (currip == '^') /* strip away the '^' */
551
{ al2_nextnw(); }
552
553
if (isdigit(currip) || currip == '-' || currip == '+')
554
{
555
if (currip == '+')
556
{
557
al2_nextnw();
558
if (!galpha && !isdigit(currip))
559
{ al2_restart("'+' must be followed by exponent number"); }
560
}
561
else if (currip == '-')
562
{
563
al2_invwrd(beg, len);
564
al2_nextnw();
565
if (!galpha && !isdigit(currip))
566
{ al2_restart("'-' must be followed by exponent number"); }
567
}
568
569
/* If we're using alphabetic generators & dropping the "^", then
570
"a^-1" can be coded as "a-", so we might not have a digit here.
571
We'll fall through, using the element as already parsed! */
572
573
if (isdigit(currip))
574
{
575
currexp = al2_readuint();
576
for (i = 2; i <= currexp; i++)
577
{ al2_addwrd(beg + (i-1)*len, beg, len); }
578
len = len*currexp;
579
}
580
}
581
else if (isalpha(currip) || currip == '(' || currip == '[')
582
{
583
/* This is sneaky! */
584
585
len2 = al2_pelt(beg+len);
586
al2_addwrd(beg+len+len2, beg+len, len2);
587
al2_invwrd(beg, len);
588
al2_invwrd(beg, len+len2);
589
len = len2 + len + len2;
590
}
591
else
592
{ al2_restart("'^' must be followed by exponent or element"); }
593
}
594
595
return len;
596
}
597
598
/******************************************************************
599
int al2_pwrd(int beg)
600
601
Parses a word into currword starting at position beg. Words are
602
defined by the following BNF:
603
604
<word> = <factor> { "*" | "/" <factor> }
605
606
The "*" can be dropped everywhere; but of course two numeric
607
generators, or a numeric exponent and a numeric generator, must be
608
separated by a whitespace.
609
610
We use currexp to help detect when a relator/generator of the form
611
x^2/X^2 (or one of its variants) has been entered. At the _start_
612
of every word we prime it to 1.
613
******************************************************************/
614
615
int al2_pwrd(int beg)
616
{
617
int len, len2;
618
char ch;
619
620
if (beg == 0)
621
{ currexp = 1; }
622
623
len = al2_pfact(beg);
624
625
while ( currip == '*' || currip == '/' || isalpha(currip) ||
626
isdigit(currip) || currip == '+' || currip == '-' ||
627
currip == '(' || currip == '[' )
628
{
629
if (currip == '*')
630
{
631
ch = '*';
632
al2_nextnw();
633
}
634
else if (currip == '/')
635
{
636
ch = '/';
637
al2_nextnw();
638
}
639
else
640
{ ch = '*'; }
641
642
len2 = al2_pfact(beg+len);
643
if (ch == '/')
644
{ al2_invwrd(beg+len, len2); }
645
len += len2;
646
}
647
648
return len;
649
}
650
651
/******************************************************************
652
Wlelt *al2_rdwrd(void)
653
654
This parses a word into currword, copies it into a properly setup
655
new word-list element, and returns a pointer to it.
656
******************************************************************/
657
658
Wlelt *al2_rdwrd(void)
659
{ return(al2_newwrd(al2_pwrd(0))); }
660
661
/******************************************************************
662
void al2_pawrd(Wlist *p)
663
664
Parse a word and add it to the list of words.
665
******************************************************************/
666
667
void al2_pawrd(Wlist *p)
668
{ al1_addwl(p, al2_rdwrd()); }
669
670
/******************************************************************
671
Wlist *al2_rdwl(void)
672
673
Reads and returns a list of words.
674
******************************************************************/
675
676
Wlist *al2_rdwl(void)
677
{
678
Wlist *p;
679
680
if ((p = al1_newwl()) == NULL) /* allocate a new list of words */
681
{ al2_continue("unable to create new word-list"); }
682
683
if (currip != ';') /* parse a sequence of words */
684
{
685
al2_pawrd(p);
686
while (currip == ',')
687
{
688
al2_nextnw();
689
al2_pawrd(p);
690
}
691
}
692
693
return(p); /* return the list of words */
694
}
695
696
/******************************************************************
697
void al2_parel(Wlist *l)
698
699
Note that W1 = W2 = W3 becomes W1W2' & W1W3'!
700
******************************************************************/
701
702
void al2_parel(Wlist *l)
703
{
704
int len1, len2;
705
706
len1 = al2_pwrd(0); /* parse left hand side word */
707
708
len2 = 0;
709
while (currip == '=') /* parse a sequence of right-hand sides */
710
{
711
al2_nextnw();
712
len2 = al2_pwrd(len1);
713
al2_invwrd(len1, len2);
714
al1_addwl(l, al2_newwrd(len1+len2));
715
}
716
717
if (len2 == 0) /* no RH side, take LH side as relator */
718
{ al1_addwl(l, al2_newwrd(len1)); }
719
}
720
721
/******************************************************************
722
Wlist *al2_rdrl(void)
723
724
Reads and returns a list of relators. Note that this is _not_ the
725
same as a list of words (ie, subgroup generators) since we're
726
allowed things like W1 = W2. So we have to invoke the parser via
727
the parse relator function _parel().
728
******************************************************************/
729
730
Wlist *al2_rdrl(void)
731
{
732
Wlist *p;
733
734
if ((p = al1_newwl()) == NULL) /* allocate a new list of words */
735
{ al2_continue("unable to create new word-list"); }
736
737
if (currip != ';')
738
{
739
al2_parel(p);
740
while (currip == ',')
741
{
742
al2_nextnw();
743
al2_parel(p);
744
}
745
}
746
747
return(p);
748
}
749
750
/******************************************************************
751
void al2_cmdloop(void)
752
******************************************************************/
753
754
void al2_cmdloop(void)
755
{
756
int i,j,k;
757
Wlist *p;
758
Logic f, li, lj;
759
760
while (TRUE)
761
{
762
/* Do the necessary for the next command (or end-of-file). Note that
763
the next command may follow on the same line, or we may have to skip
764
over a '\n' to the next line. (Not sure if this is bomb-proof under
765
all (error) conditions.) */
766
767
al2_nextnw();
768
skipnl = TRUE;
769
al2_skipws();
770
skipnl = FALSE;
771
772
if (currip == EOF)
773
{ break; }
774
775
al2_readkey();
776
777
/* The work-horse; just plow through until the first match, do it,
778
and then skip to the end of the while(). */
779
780
if (al2_match("add gen[erators]") || al2_match("sg"))
781
{
782
if (ndgen < 1)
783
{ al2_continue("there are no generators as yet"); }
784
785
skipnl = TRUE;
786
al2_skipws();
787
788
p = al2_rdwl();
789
al2_endcmd();
790
791
if (genlst == NULL)
792
{ genlst = p; }
793
else
794
{ al1_concatwl(genlst,p); }
795
796
nsgpg = genlst->len;
797
798
okcont = FALSE;
799
tabinfo = tabindex = FALSE;
800
801
continue;
802
}
803
804
if (al2_match("add rel[ators]") || al2_match("rl"))
805
{
806
if (ndgen < 1)
807
{ al2_continue("there are no generators as yet"); }
808
809
skipnl = TRUE;
810
al2_skipws();
811
812
p = al2_rdrl();
813
al2_endcmd();
814
815
if (rellst == NULL)
816
{ rellst = p; }
817
else
818
{ al1_concatwl(rellst,p); }
819
820
ndrel = rellst->len;
821
822
okcont = FALSE;
823
tabindex = FALSE;
824
825
continue;
826
}
827
828
/* All Equivalent Presentations */
829
830
if (al2_match("aep"))
831
{
832
al2_readia();
833
al2_endcmd();
834
835
if (intcnt != 1)
836
{ al2_continue("bad number of parameters"); }
837
if (intarr[0] < 1 || intarr[0] > 7)
838
{ al2_continue("invalid first argument"); }
839
840
if (!okstart)
841
{ al2_continue("can't start (no generators/workspace)"); }
842
if (rellst == NULL || rellst->len == 0)
843
{ al2_continue("can't start (no relators)"); }
844
845
al2_aep(intarr[0]);
846
847
continue;
848
}
849
850
if (al2_match("ai") || al2_match("alter i[nput]"))
851
{
852
al2_readname();
853
al2_endcmd();
854
855
if (strlen(currname) == 0)
856
{ strcpy(currname, "stdin"); }
857
al2_aip(currname);
858
859
continue;
860
}
861
862
if (al2_match("ao") || al2_match("alter o[utput]"))
863
{
864
al2_readname();
865
al2_endcmd();
866
867
if (strlen(currname) == 0)
868
{ strcpy(currname, "stdout"); }
869
al2_aop(currname);
870
871
continue;
872
}
873
874
/* What to do with asis in continue/redo? It's (current) value in a
875
printout may not match that actually used at the start of a run, when
876
the involutary generators are picked up & the columns allocated, and
877
these settings are frozen until the next start/begin/end! */
878
879
if (al2_match("as[is]"))
880
{
881
al2_readia();
882
al2_endcmd();
883
884
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )
885
{ al2_continue("bad parameter"); }
886
else if (intcnt == 0)
887
{ fprintf(fop, "asis = %s\n", asis ? "true" : "false"); }
888
else
889
{ asis = (intarr[0] == 1); }
890
891
continue;
892
}
893
894
if (al2_match("beg[in]") || al2_match("end") || al2_match("start"))
895
{
896
al2_endcmd();
897
898
if (!okstart)
899
{ al2_continue("can't start (no generators?)"); }
900
901
al1_rslt(lresult = al1_start(0));
902
903
/* If something `sensible' happened, then it'll be ok to continue or
904
redo this run. If not, then we make sure that we must begin a new
905
run. Note that here (& in continue/redo) we play it safe by
906
enforcing a new run, even if there may be no need to. Note that the
907
SG phase is 1st in start mode, so should _always_ be done. */
908
909
if (lresult > 0 && sgdone) /* finite index */
910
{
911
okcont = okredo = TRUE;
912
tabinfo = tabindex = TRUE;
913
}
914
else if (lresult >= -259 && sgdone) /* holey/overflow/limit */
915
{
916
okcont = okredo = TRUE;
917
tabinfo = TRUE;
918
tabindex = FALSE;
919
}
920
else /* SG overflow/`error' */
921
{
922
okcont = okredo = FALSE;
923
tabinfo = tabindex = FALSE;
924
}
925
926
continue;
927
}
928
929
if (al2_match("bye") || al2_match("exit") || al2_match("q[uit]"))
930
{
931
al2_endcmd();
932
933
break;
934
}
935
936
if (al2_match("cc") || al2_match("coset coinc[idence]"))
937
{
938
al2_readia();
939
al2_endcmd();
940
941
if (intcnt != 1)
942
{ al2_continue("bad number of parameters"); }
943
if (!tabinfo)
944
{ al2_continue("there is no table information"); }
945
if (intarr[0] < 2 || intarr[0] >= nextdf || COL1(intarr[0]) < 0)
946
{ al2_continue("invalid/redundant coset number"); }
947
948
al2_cc(intarr[0]);
949
950
continue;
951
}
952
953
if (al2_match("c[factor]") || al2_match("ct[ factor]"))
954
{
955
al2_readia();
956
al2_endcmd();
957
958
if (intcnt > 1)
959
{ al2_continue("bad parameter"); }
960
else if (intcnt == 0)
961
{ fprintf(fop, "ct factor = %d\n", cfactor1); }
962
else
963
{ cfactor1 = intarr[0]; }
964
965
continue;
966
}
967
968
/* See comments for "begin". */
969
970
if (al2_match("check") || al2_match("redo"))
971
{
972
al2_endcmd();
973
974
if (!okredo)
975
{ al2_continue("can't redo (different presentation?)"); }
976
977
al1_rslt(lresult = al1_start(2));
978
979
if (lresult > 0 && sgdone)
980
{
981
okcont = TRUE;
982
tabinfo = tabindex = TRUE;
983
}
984
else if (lresult >= -259 && sgdone)
985
{
986
okcont = TRUE;
987
tabinfo = TRUE;
988
tabindex = FALSE;
989
}
990
else
991
{
992
okcont = FALSE;
993
tabinfo = tabindex = FALSE;
994
}
995
if (lresult < -260)
996
{ okredo = FALSE; }
997
998
continue;
999
}
1000
1001
if (al2_match("com[paction]"))
1002
{
1003
al2_readia();
1004
al2_endcmd();
1005
1006
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 100)) ||
1007
intcnt > 1 )
1008
{ al2_continue("bad parameter"); }
1009
else if (intcnt == 0)
1010
{ fprintf(fop, "compaction = %d\n", comppc); }
1011
else
1012
{ comppc = intarr[0]; }
1013
1014
continue;
1015
}
1016
1017
/* See comments for "begin". */
1018
1019
if (al2_match("con[tinue]"))
1020
{
1021
al2_endcmd();
1022
1023
if (!okcont)
1024
{ al2_continue("can't continue (altered presentation?)"); }
1025
1026
al1_rslt(lresult = al1_start(1));
1027
1028
if (lresult > 0 && sgdone)
1029
{ tabinfo = tabindex = TRUE; }
1030
else if (lresult >= -259 && sgdone)
1031
{
1032
tabinfo = TRUE;
1033
tabindex = FALSE;
1034
}
1035
else
1036
{
1037
okcont = FALSE;
1038
tabinfo = tabindex = FALSE;
1039
}
1040
1041
continue;
1042
}
1043
1044
if (al2_match("cy[cles]"))
1045
{
1046
al2_endcmd();
1047
1048
if (!tabindex)
1049
{ al2_continue("there is no completed table"); }
1050
1051
begintime = al0_clock();
1052
li = al0_compact();
1053
endtime = al0_clock();
1054
if (li)
1055
{ fprintf(fop, "CO"); }
1056
else
1057
{ fprintf(fop, "co"); }
1058
fprintf(fop, ": a=%d r=%d h=%d n=%d; c=+%4.2f\n",
1059
nalive, knr, knh, nextdf, al0_diff(begintime,endtime));
1060
1061
al2_cycles();
1062
1063
continue;
1064
}
1065
1066
if (al2_match("ded mo[de]") || al2_match("dmod[e]"))
1067
{
1068
al2_readia();
1069
al2_endcmd();
1070
1071
if (intcnt == 0)
1072
{ fprintf(fop, "deduction mode = %d\n", dedmode); }
1073
else if (intcnt == 1)
1074
{
1075
if (intarr[0] < 0 || intarr[0] > 4)
1076
{ al2_continue("bad mode parameter"); }
1077
dedmode = intarr[0];
1078
}
1079
else
1080
{ al2_continue("bad parameter count"); }
1081
1082
continue;
1083
}
1084
1085
if (al2_match("ded si[ze]") || al2_match("dsiz[e]"))
1086
{
1087
al2_readia();
1088
al2_endcmd();
1089
1090
if ( (intcnt > 0 && intarr[0] < 0) || intcnt > 1 )
1091
{ al2_continue("bad parameter"); }
1092
else if (intcnt == 0)
1093
{ fprintf(fop, "deduction stack = %d\n", dedsiz1); }
1094
else
1095
{ dedsiz1 = intarr[0]; }
1096
1097
continue;
1098
}
1099
1100
if (al2_match("def[ault]"))
1101
{
1102
al2_endcmd();
1103
1104
cfactor1 = 0;
1105
comppc = 10;
1106
dedmode = 4;
1107
dedsiz1 = 1000;
1108
ffactor1 = 0;
1109
lahead = 0;
1110
mendel = FALSE;
1111
nrinsgp1 = -1;
1112
pdefn = 3;
1113
pdsiz1 = 256;
1114
rfactor1 = 0;
1115
rfill = TRUE;
1116
pcomp = FALSE;
1117
1118
continue;
1119
}
1120
1121
if (al2_match("del gen[erators]") || al2_match("ds"))
1122
{
1123
al2_readia();
1124
al2_endcmd();
1125
1126
if (intcnt < 1 || genlst == NULL || genlst->len < 1)
1127
{ al2_continue("empty argument list / generator list"); }
1128
al2_dw(genlst);
1129
nsgpg = genlst->len;
1130
1131
okcont = okredo = FALSE;
1132
tabinfo = tabindex = FALSE;
1133
1134
continue;
1135
}
1136
1137
if (al2_match("del rel[ators]") || al2_match("dr"))
1138
{
1139
al2_readia();
1140
al2_endcmd();
1141
1142
if (intcnt < 1 || rellst == NULL || rellst->len < 1)
1143
{ al2_continue("empty argument list / relator list"); }
1144
al2_dw(rellst);
1145
ndrel = rellst->len;
1146
1147
okcont = okredo = FALSE;
1148
tabinfo = tabindex = FALSE;
1149
1150
continue;
1151
}
1152
1153
if (al2_match("d[ump]"))
1154
{
1155
al2_readia();
1156
al2_endcmd();
1157
1158
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 2)) ||
1159
(intcnt > 1 && (intarr[1] < 0 || intarr[1] > 1)) ||
1160
intcnt > 2 )
1161
{ al2_continue("bad parameters"); }
1162
else if (intcnt == 0)
1163
{ al0_dump(FALSE); }
1164
else if (intcnt == 1)
1165
{
1166
if (intarr[0] == 0)
1167
{ al0_dump(FALSE); }
1168
else if (intarr[0] == 1)
1169
{ al1_dump(FALSE); }
1170
else
1171
{ al2_dump(FALSE); }
1172
}
1173
else
1174
{
1175
if (intarr[0] == 0)
1176
{ al0_dump(intarr[1] == 1); }
1177
else if (intarr[0] == 1)
1178
{ al1_dump(intarr[1] == 1); }
1179
else
1180
{ al2_dump(intarr[1] == 1); }
1181
}
1182
1183
continue;
1184
}
1185
1186
if (al2_match("easy"))
1187
{
1188
al2_endcmd();
1189
1190
cfactor1 = 0;
1191
comppc = 100;
1192
dedmode = 0;
1193
dedsiz1 = 1000;
1194
ffactor1 = 1;
1195
lahead = 0;
1196
mendel = FALSE;
1197
nrinsgp1 = 0;
1198
pdefn = 0;
1199
pdsiz1 = 256;
1200
rfactor1 = 1000;
1201
rfill = TRUE;
1202
pcomp = FALSE;
1203
1204
continue;
1205
}
1206
1207
if (al2_match("echo"))
1208
{
1209
al2_readia();
1210
al2_endcmd();
1211
1212
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )
1213
{ al2_continue("bad parameter"); }
1214
else if (intcnt == 0)
1215
{ fprintf(fop, "echo = %s\n", echo ? "true" : "false"); }
1216
else
1217
{ echo = (intarr[0] == 1); }
1218
1219
continue;
1220
}
1221
1222
/* Note that it is ok to set the name to "". If the call to _strdup()
1223
fails, then _continue() will be invoked. This could leave grpname
1224
still pointing to freed storage, hence the explicit setting to NULL. */
1225
1226
if (al2_match("enum[eration]") || al2_match("group name"))
1227
{
1228
al2_readname();
1229
al2_endcmd();
1230
1231
if (grpname != NULL)
1232
{ free(grpname); }
1233
grpname = NULL;
1234
grpname = al2_strdup(currname);
1235
1236
continue;
1237
}
1238
1239
if (al2_match("fel[sch]"))
1240
{
1241
al2_readia();
1242
al2_endcmd();
1243
1244
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )
1245
{ al2_continue("bad parameter"); }
1246
1247
if (intcnt == 1 && intarr[0] == 1) /* `Enhanced' Felsch */
1248
{
1249
ffactor1 = 0;
1250
nrinsgp1 = -1;
1251
pdefn = 3;
1252
}
1253
else /* Felsch (~ Pure C) */
1254
{
1255
ffactor1 = 1;
1256
nrinsgp1 = 0;
1257
pdefn = 0;
1258
}
1259
1260
cfactor1 = 1000;
1261
comppc = 10;
1262
dedmode = 4;
1263
dedsiz1 = 1000;
1264
lahead = 0;
1265
mendel = FALSE;
1266
pdsiz1 = 256;
1267
rfactor1 = 0;
1268
rfill = FALSE;
1269
pcomp = FALSE;
1270
1271
continue;
1272
}
1273
1274
/* If you set this to 0, Level 1 will set ffactor to a `sensible'
1275
default (eg, 5(ncol+2)/4). */
1276
1277
if (al2_match("f[factor]") || al2_match("fi[ll factor]"))
1278
{
1279
al2_readia();
1280
al2_endcmd();
1281
1282
if ( (intcnt > 0 && intarr[0] < 0) || intcnt > 1 )
1283
{ al2_continue("bad parameter"); }
1284
else if (intcnt == 0)
1285
{ fprintf(fop, "fill factor = %d\n", ffactor1); }
1286
else
1287
{ ffactor1 = intarr[0]; }
1288
1289
continue;
1290
}
1291
1292
if (al2_match("gen[erators]") || al2_match("subgroup gen[erators]"))
1293
{
1294
if (ndgen < 1)
1295
{ al2_continue("there are no generators as yet"); }
1296
1297
skipnl = TRUE;
1298
al2_skipws();
1299
1300
p = al2_rdwl();
1301
al2_endcmd();
1302
1303
if (genlst != NULL)
1304
{ al1_emptywl(genlst); free(genlst); }
1305
genlst = p;
1306
nsgpg = p->len;
1307
1308
okcont = okredo = FALSE;
1309
tabinfo = tabindex = FALSE;
1310
1311
continue;
1312
}
1313
1314
if (al2_match("gr[oup generators]"))
1315
{
1316
if (isdigit(currip) || currip == '+' || currip == '-')
1317
{
1318
i = al2_readint();
1319
al2_endcmd();
1320
if (i < 1)
1321
{ al2_continue("bad parameter"); }
1322
1323
ndgen = i;
1324
galpha = FALSE;
1325
1326
okstart = (costable != NULL);
1327
okcont = okredo = FALSE;
1328
tabinfo = tabindex = FALSE;
1329
1330
/* The current relator & generator lists are now invalid */
1331
1332
if (rellst != NULL)
1333
{ al1_emptywl(rellst); free(rellst); }
1334
rellst = NULL;
1335
ndrel = 0;
1336
if (genlst != NULL)
1337
{ al1_emptywl(genlst); free(genlst); }
1338
genlst = NULL;
1339
nsgpg = 0;
1340
}
1341
else if (isalpha(currip))
1342
{
1343
i = al2_readgen();
1344
al2_endcmd();
1345
1346
ndgen = i;
1347
galpha = TRUE;
1348
for (j = 1; j <= ndgen; j++)
1349
{ algen[j] = currname[j]; }
1350
algen[ndgen+1] = '\0'; /* &algen[1] is printable string */
1351
1352
for (j = 1; j <= 26; j++)
1353
{ genal[j] = 0;}
1354
for (j = 1; j <= ndgen; j++)
1355
{ genal[algen[j]-'a'+1] = j; }
1356
1357
okstart = (costable != NULL);
1358
okcont = okredo = FALSE;
1359
tabinfo = tabindex = FALSE;
1360
1361
if (rellst != NULL)
1362
{ al1_emptywl(rellst); free(rellst); }
1363
rellst = NULL;
1364
ndrel = 0;
1365
if (genlst != NULL)
1366
{ al1_emptywl(genlst); free(genlst); }
1367
genlst = NULL;
1368
nsgpg = 0;
1369
}
1370
else
1371
{
1372
al2_endcmd();
1373
1374
fprintf(fop, "group generators = ");
1375
if (ndgen < 1)
1376
{ fprintf(fop, "none\n"); }
1377
else if (galpha)
1378
{
1379
for (i = 1; i <= ndgen; i++)
1380
{ fprintf(fop, "%c", algen[i]); }
1381
fprintf(fop, "\n");
1382
}
1383
else
1384
{ fprintf(fop, "1..%d\n", ndgen); }
1385
}
1386
1387
continue;
1388
}
1389
1390
if (al2_match("group relators") || al2_match("rel[ators]"))
1391
{
1392
if (ndgen < 1)
1393
{ al2_continue("there are no generators as yet"); }
1394
1395
skipnl = TRUE;
1396
al2_skipws();
1397
1398
p = al2_rdrl();
1399
al2_endcmd();
1400
1401
if (rellst != NULL)
1402
{ al1_emptywl(rellst); free(rellst); }
1403
rellst = p;
1404
ndrel = p->len;
1405
1406
okcont = okredo = FALSE;
1407
tabinfo = tabindex = FALSE;
1408
1409
continue;
1410
}
1411
1412
if (al2_match("hard"))
1413
{
1414
al2_endcmd();
1415
1416
cfactor1 = 1000;
1417
comppc = 10;
1418
dedmode = 4;
1419
dedsiz1 = 1000;
1420
ffactor1 = 0;
1421
lahead = 0;
1422
mendel = FALSE;
1423
nrinsgp1 = -1;
1424
pdefn = 3;
1425
pdsiz1 = 256;
1426
rfactor1 = 1;
1427
rfill = TRUE;
1428
pcomp = FALSE;
1429
1430
continue;
1431
}
1432
1433
if (al2_match("h[elp]"))
1434
{
1435
al2_endcmd();
1436
al2_help();
1437
1438
continue;
1439
}
1440
1441
if (al2_match("hlt"))
1442
{
1443
al2_endcmd();
1444
1445
cfactor1 = 0;
1446
comppc = 10;
1447
dedmode = 0;
1448
dedsiz1 = 1000;
1449
ffactor1 = 1;
1450
lahead = 1;
1451
mendel = FALSE;
1452
nrinsgp1 = 0;
1453
pdefn = 0;
1454
pdsiz1 = 256;
1455
rfactor1 = 1000;
1456
rfill = TRUE;
1457
pcomp = FALSE;
1458
1459
continue;
1460
}
1461
1462
if (al2_match("ho[le limit]"))
1463
{
1464
al2_readia();
1465
al2_endcmd();
1466
1467
if ( (intcnt > 0 && (intarr[0] < -1 || intarr[0] > 100)) ||
1468
intcnt > 1 )
1469
{ al2_continue("bad parameter"); }
1470
else if (intcnt == 0)
1471
{ fprintf(fop, "hole limit = %d\n", hlimit); }
1472
else
1473
{ hlimit = intarr[0]; }
1474
1475
continue;
1476
}
1477
1478
if (al2_match("look[ahead]"))
1479
{
1480
al2_readia();
1481
al2_endcmd();
1482
1483
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 4)) || intcnt > 1 )
1484
{ al2_continue("bad parameter"); }
1485
else if (intcnt == 0)
1486
{ fprintf(fop, "lookahead = %d\n", lahead); }
1487
else
1488
{ lahead = intarr[0]; }
1489
1490
continue;
1491
}
1492
1493
if (al2_match("loop[ limit]"))
1494
{
1495
al2_readia();
1496
al2_endcmd();
1497
1498
if ( (intcnt > 0 && intarr[0] < 0) || intcnt > 1 )
1499
{ al2_continue("bad parameter"); }
1500
else if (intcnt == 0)
1501
{ fprintf(fop, "loop limit = %d\n", llimit); }
1502
else
1503
{ llimit = intarr[0]; }
1504
1505
continue;
1506
}
1507
1508
if (al2_match("max[ cosets]"))
1509
{
1510
al2_readia();
1511
al2_endcmd();
1512
1513
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] == 1)) ||
1514
intcnt > 1 )
1515
{ al2_continue("bad parameter"); }
1516
else if (intcnt == 0)
1517
{ fprintf(fop, "max cosets = %d\n", maxrow1); }
1518
else
1519
{ maxrow1 = intarr[0]; }
1520
1521
continue;
1522
}
1523
1524
if (al2_match("mess[ages]") || al2_match("mon[itor]"))
1525
{
1526
al2_readia();
1527
al2_endcmd();
1528
1529
if (intcnt > 1)
1530
{ al2_continue("too many parameters"); }
1531
else if (intcnt == 0)
1532
{
1533
if (msgctrl)
1534
{
1535
if (msghol)
1536
{ fprintf(fop, "messages = %d (+ holes)\n", msgincr); }
1537
else
1538
{ fprintf(fop, "messages = %d (- holes)\n", msgincr); }
1539
}
1540
else
1541
{ fprintf(fop, "messages = off\n"); }
1542
}
1543
else if (intarr[0] == 0)
1544
{
1545
msgctrl = FALSE;
1546
msghol = FALSE;
1547
msgincr = 0;
1548
}
1549
else if (intarr[0] < 0)
1550
{
1551
msgctrl = TRUE;
1552
msghol = TRUE;
1553
msgincr = -intarr[0];
1554
}
1555
else
1556
{
1557
msgctrl = TRUE;
1558
msghol = FALSE;
1559
msgincr = intarr[0];
1560
}
1561
1562
continue;
1563
}
1564
1565
if (al2_match("mend[elsohn]"))
1566
{
1567
al2_readia();
1568
al2_endcmd();
1569
1570
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )
1571
{ al2_continue("bad parameter"); }
1572
else if (intcnt == 0)
1573
{ fprintf(fop, "mendelsohn = %s\n", mendel ? "true" : "false"); }
1574
else
1575
{ mendel = (intarr[0] == 1); }
1576
1577
continue;
1578
}
1579
1580
if (al2_match("mo[de]"))
1581
{
1582
al2_endcmd();
1583
1584
if (okstart)
1585
{ fprintf(fop, "start = yes,"); }
1586
else
1587
{ fprintf(fop, "start = no,"); }
1588
if (okcont)
1589
{ fprintf(fop, " continue = yes,"); }
1590
else
1591
{ fprintf(fop, " continue = no,"); }
1592
if (okredo)
1593
{ fprintf(fop, " redo = yes\n"); }
1594
else
1595
{ fprintf(fop, " redo = no\n"); }
1596
1597
continue;
1598
}
1599
1600
if (al2_match("nc") || al2_match("normal[ closure]"))
1601
{
1602
al2_readia();
1603
al2_endcmd();
1604
1605
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )
1606
{ al2_continue("bad parameter"); }
1607
if (!tabinfo)
1608
{ al2_continue("there is no table information"); }
1609
1610
begintime = al0_clock();
1611
li = al0_compact();
1612
endtime = al0_clock();
1613
if (li)
1614
{ fprintf(fop, "CO"); }
1615
else
1616
{ fprintf(fop, "co"); }
1617
fprintf(fop, ": a=%d r=%d h=%d n=%d; c=+%4.2f\n",
1618
nalive, knr, knh, nextdf, al0_diff(begintime,endtime));
1619
1620
if (intcnt == 0)
1621
{ al2_normcl(FALSE); }
1622
else
1623
{ al2_normcl(intarr[0] == 1); }
1624
1625
continue;
1626
}
1627
1628
if (al2_match("no[ relators in subgroup]"))
1629
{
1630
al2_readia();
1631
al2_endcmd();
1632
1633
if ( (intcnt > 0 && intarr[0] < -1) || intcnt > 1 )
1634
{ al2_continue("bad parameter"); }
1635
else if (intcnt == 0)
1636
{ fprintf(fop, "no. rels in subgr = %d\n", nrinsgp1); }
1637
else
1638
{ nrinsgp1 = intarr[0]; }
1639
1640
continue;
1641
}
1642
1643
if (al2_match("oo") || al2_match("order[ option]"))
1644
{
1645
al2_readia();
1646
al2_endcmd();
1647
1648
if (intcnt != 1)
1649
{ al2_continue("missing argument / too many arguments"); }
1650
if (!tabinfo)
1651
{ al2_continue("no information in table"); }
1652
1653
al2_oo(intarr[0]);
1654
1655
continue;
1656
}
1657
1658
if (al2_match("opt[ions]"))
1659
{
1660
al2_endcmd();
1661
al2_opt();
1662
1663
continue;
1664
}
1665
1666
/* an old command, which we quietly ignore */
1667
1668
if (al2_match("par[ameters]"))
1669
{
1670
al2_endcmd();
1671
continue;
1672
}
1673
1674
if (al2_match("path[ compression]"))
1675
{
1676
al2_readia();
1677
al2_endcmd();
1678
1679
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )
1680
{ al2_continue("bad parameter"); }
1681
else if (intcnt == 0)
1682
{ fprintf(fop, "path compression = %s\n", pcomp ? "on" : "off"); }
1683
else
1684
{ pcomp = (intarr[0] == 1); }
1685
1686
continue;
1687
}
1688
1689
if (al2_match("pd mo[de]") || al2_match("pmod[e]"))
1690
{
1691
al2_readia();
1692
al2_endcmd();
1693
1694
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 3)) || intcnt > 1 )
1695
{ al2_continue("bad parameter"); }
1696
else if (intcnt == 0)
1697
{ fprintf(fop, "pref. definition mode = %d\n", pdefn); }
1698
else
1699
{ pdefn = intarr[0]; }
1700
1701
continue;
1702
}
1703
1704
if (al2_match("pd si[ze]") || al2_match("psiz[e]"))
1705
{
1706
al2_readia();
1707
al2_endcmd();
1708
1709
if ( (intcnt > 0 && intarr[0] < 0) || intcnt > 1 )
1710
{ al2_continue("bad parameter"); }
1711
else if (intcnt == 0)
1712
{ fprintf(fop, "pref. definition list = %d\n", pdsiz1); }
1713
else if (intarr[0] == 0)
1714
{ pdsiz1 = intarr[0]; } /* use default value */
1715
else if (intarr[0]%2 == 1)
1716
{ al2_continue("bad parameter"); } /* odd (incl. 1) */
1717
else
1718
{ /* even parameter, >= 2 */
1719
i = intarr[0];
1720
while (i%2 == 0)
1721
{ i /= 2; }
1722
if (i == 1)
1723
{ pdsiz1 = intarr[0]; }
1724
else
1725
{ al2_continue("bad parameter"); } /* not power of 2 */
1726
}
1727
1728
continue;
1729
}
1730
1731
if (al2_match("print det[ails]") || al2_match("sr"))
1732
{
1733
al2_readia();
1734
al2_endcmd();
1735
1736
if ((intcnt > 0 && (intarr[0] < 0 || intarr[0] > 5)) || intcnt > 1)
1737
{ al2_continue("bad parameter"); }
1738
else if (intcnt == 0)
1739
{ al1_prtdetails(0); }
1740
else
1741
{ al1_prtdetails(intarr[0]); }
1742
1743
continue;
1744
}
1745
1746
/* Negative first parameter means include order/rep, else don't. No
1747
parameters means all the table, one parameter "x" means (1,x,1), two
1748
parameters "x,y" means (x,y,1), and three parameters "x,y,z" means
1749
(x,y,z). Note the compulsory compaction, to prevent utterly confusing
1750
the user! (This may cause disded to become true.) */
1751
1752
if (al2_match("pr[int table]"))
1753
{
1754
al2_readia();
1755
al2_endcmd();
1756
1757
if (!tabinfo)
1758
{ al2_continue("no information in table"); }
1759
1760
if (intcnt == 0)
1761
{
1762
f = FALSE;
1763
intarr[0] = 1;
1764
intarr[1] = nextdf-1;
1765
intarr[2] = 1;
1766
}
1767
else if (intcnt <= 3)
1768
{
1769
if (intarr[0] < 0)
1770
{
1771
f = TRUE;
1772
intarr[0] = -intarr[0];
1773
}
1774
else
1775
{ f = FALSE; }
1776
}
1777
else
1778
{ al2_continue("too many parameters"); }
1779
1780
if (intcnt == 1)
1781
{
1782
intarr[1] = intarr[0];
1783
intarr[0] = intarr[2] = 1;
1784
}
1785
else if (intcnt == 2)
1786
{ intarr[2] = 1; }
1787
1788
if (intarr[0] >= nextdf)
1789
{ intarr[0] = nextdf-1; }
1790
if (intarr[1] >= nextdf)
1791
{ intarr[1] = nextdf-1; }
1792
1793
if (intarr[0] < 1 || intarr[1] < intarr[0] || intarr[2] < 1 )
1794
{ al2_continue("bad parameters"); }
1795
1796
begintime = al0_clock();
1797
li = al0_compact();
1798
endtime = al0_clock();
1799
if (li)
1800
{ fprintf(fop, "CO"); }
1801
else
1802
{ fprintf(fop, "co"); }
1803
fprintf(fop, ": a=%d r=%d h=%d n=%d; c=+%4.2f\n",
1804
nalive, knr, knh, nextdf, al0_diff(begintime,endtime));
1805
1806
al1_prtct(intarr[0], intarr[1], intarr[2], FALSE, f);
1807
1808
continue;
1809
}
1810
1811
if (al2_match("pure c[t]"))
1812
{
1813
al2_endcmd();
1814
1815
cfactor1 = 1000;
1816
comppc = 100;
1817
dedmode = 4;
1818
dedsiz1 = 1000;
1819
ffactor1 = 1;
1820
lahead = 0;
1821
mendel = FALSE;
1822
nrinsgp1 = 0;
1823
pdefn = 0;
1824
pdsiz1 = 256;
1825
rfactor1 = 0;
1826
rfill = FALSE;
1827
pcomp = FALSE;
1828
1829
continue;
1830
}
1831
1832
if (al2_match("pure r[t]"))
1833
{
1834
al2_endcmd();
1835
1836
cfactor1 = 0;
1837
comppc = 100;
1838
dedmode = 0;
1839
dedsiz1 = 1000;
1840
ffactor1 = 1;
1841
lahead = 0;
1842
mendel = FALSE;
1843
nrinsgp1 = 0;
1844
pdefn = 0;
1845
pdsiz1 = 256;
1846
rfactor1 = 1000;
1847
rfill = FALSE;
1848
pcomp = FALSE;
1849
1850
continue;
1851
}
1852
1853
/* This is a `dangerous' option, since it can go wrong, or `corrupt'
1854
the status, in so many ways. We try to minimise problems by being
1855
very strict as to when we allow it to be called. How much of this is
1856
necessary/desirable is moot. */
1857
1858
if (al2_match("rc") || al2_match("random coinc[idences]"))
1859
{
1860
al2_readia();
1861
al2_endcmd();
1862
1863
if (intcnt < 1 || intcnt > 2)
1864
{ al2_continue("bad number of parameters"); }
1865
if (intarr[0] < 0)
1866
{ al2_continue("invalid first argument"); }
1867
if (intcnt == 2 && intarr[1] < 1)
1868
{ al2_continue("invalid second argument"); }
1869
1870
if (!tabinfo)
1871
{ al2_continue("there is no table information"); }
1872
if (!okredo)
1873
{ al2_continue("can't redo (different presentation?)"); }
1874
1875
if (lresult == 1)
1876
{ al2_continue("trivial finite index already exists"); }
1877
1878
if (intarr[0] == 0)
1879
{
1880
if (lresult > 0)
1881
{ al2_continue("non-trivial finite index already present"); }
1882
}
1883
else
1884
{
1885
if (lresult > 0 && lresult < intarr[0])
1886
{ al2_continue("finite index already < argument"); }
1887
if (lresult > 0 && lresult%intarr[0] == 0)
1888
{ al2_continue("finite index already multiple of argument"); }
1889
}
1890
1891
if (intarr[0] >= nalive)
1892
{ al2_continue("not enough active cosets available"); }
1893
1894
if (intcnt == 1) /* Try 8 times, by default */
1895
{ al2_rc(intarr[0],8); }
1896
else
1897
{ al2_rc(intarr[0],intarr[1]); }
1898
1899
continue;
1900
}
1901
1902
if (al2_match("rec[over]") || al2_match("contig[uous]"))
1903
{
1904
if (!tabinfo)
1905
{ al2_continue("there is no table information"); }
1906
1907
begintime = al0_clock();
1908
li = al0_compact();
1909
endtime = al0_clock();
1910
if (li)
1911
{ fprintf(fop, "CO"); }
1912
else
1913
{ fprintf(fop, "co"); }
1914
fprintf(fop, ": a=%d r=%d h=%d n=%d; c=+%4.2f\n",
1915
nalive, knr, knh, nextdf, al0_diff(begintime,endtime));
1916
1917
continue;
1918
}
1919
1920
/* Random Equivalent Presentations */
1921
1922
if (al2_match("rep"))
1923
{
1924
al2_readia();
1925
al2_endcmd();
1926
1927
if (intcnt < 1 || intcnt > 2)
1928
{ al2_continue("bad number of parameters"); }
1929
if (intarr[0] < 1 || intarr[0] > 7)
1930
{ al2_continue("invalid first argument"); }
1931
if (intcnt == 2 && intarr[1] < 1)
1932
{ al2_continue("invalid second argument"); }
1933
1934
if (!okstart)
1935
{ al2_continue("can't start (no generators/workspace)"); }
1936
if (rellst == NULL || rellst->len == 0)
1937
{ al2_continue("can't start (no relators)"); }
1938
1939
if (intcnt == 1)
1940
{ al2_rep(intarr[0], 8); }
1941
else
1942
{ al2_rep(intarr[0], intarr[1]); }
1943
1944
continue;
1945
}
1946
1947
/* an old command, which we quietly ignore */
1948
1949
if (al2_match("restart"))
1950
{
1951
al2_endcmd();
1952
continue;
1953
}
1954
1955
if (al2_match("r[factor]") || al2_match("rt[ factor]"))
1956
{
1957
al2_readia();
1958
al2_endcmd();
1959
1960
if (intcnt > 1)
1961
{ al2_continue("bad parameter"); }
1962
else if (intcnt == 0)
1963
{ fprintf(fop, "rt factor = %d\n", rfactor1); }
1964
else
1965
{ rfactor1 = intarr[0]; }
1966
1967
continue;
1968
}
1969
1970
if (al2_match("row[ filling]"))
1971
{
1972
al2_readia();
1973
al2_endcmd();
1974
1975
if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )
1976
{ al2_continue("bad parameter"); }
1977
else if (intcnt == 0)
1978
{ fprintf(fop, "row fill = %s\n", rfill ? "on" : "off"); }
1979
else
1980
{ rfill = (intarr[0] == 1); }
1981
1982
continue;
1983
}
1984
1985
if (al2_match("sc") || al2_match("stabil[ising cosets]"))
1986
{
1987
al2_readia();
1988
al2_endcmd();
1989
1990
if (intcnt != 1)
1991
{ al2_continue("missing argument / too many arguments"); }
1992
if (!tabinfo)
1993
{ al2_continue("no information in table"); }
1994
1995
al2_sc(intarr[0]);
1996
1997
continue;
1998
}
1999
2000
/* We emulate, as best we can, the odd-numbered enumeration strategies
2001
given in Table 5.5.1 (p. 245) of C.C. Sims' book. The even-numbered
2002
ones involve `standardise-as-you-go', which we don't do; however we can
2003
standardise the table once we're done, or we can pause an enumeration
2004
at any time, standardise, and then continue. (This last is not as daft
2005
as it seems and does, in fact, sometimes prove beneficial.) The
2006
strategies are: 1) HLT, no save; 3) HLT, save; 5) CHLT, no save; 7)
2007
CHLT, save; 9) Felsch (save). */
2008
2009
if (al2_match("sims"))
2010
{
2011
al2_readia();
2012
al2_endcmd();
2013
2014
if ( intcnt != 1 ||
2015
intarr[0] < 1 || intarr[0] > 9 || intarr[0]%2 == 0 )
2016
{ al2_continue("bad parameter"); }
2017
2018
switch(intarr[0])
2019
{
2020
case 1: /* cf. "pure r" + row-fill */
2021
cfactor1 = 0;
2022
dedmode = 0;
2023
mendel = FALSE;
2024
rfactor1 = 1000;
2025
rfill = TRUE;
2026
break;
2027
case 3:
2028
cfactor1 = 0;
2029
dedmode = 4;
2030
mendel = FALSE;
2031
rfactor1 = -1000;
2032
rfill = TRUE;
2033
break;
2034
case 5:
2035
cfactor1 = 0;
2036
dedmode = 0;
2037
mendel = TRUE;
2038
rfactor1 = 1000;
2039
rfill = TRUE;
2040
break;
2041
case 7:
2042
cfactor1 = 0;
2043
dedmode = 4;
2044
mendel = TRUE;
2045
rfactor1 = -1000;
2046
rfill = TRUE;
2047
break;
2048
case 9: /* cf. "pure c" / "Felsch" */
2049
cfactor1 = 1000;
2050
dedmode = 4;
2051
mendel = FALSE;
2052
rfactor1 = 0;
2053
rfill = FALSE;
2054
break;
2055
}
2056
2057
/* These parameters are common to all modes. */
2058
2059
comppc = 10; /* compaction always allowed */
2060
dedsiz1 = 1000; /* default (starting) size */
2061
ffactor1 = 1; /* fill-factor not active */
2062
lahead = 0; /* never lookahead */
2063
nrinsgp1 = 0; /* no (active) RS phase */
2064
pdefn = 0; /* no preferred/immediate defns ... */
2065
pdsiz1 = 256;
2066
pcomp = FALSE;
2067
2068
continue;
2069
}
2070
2071
if (al2_match("st[andard table]"))
2072
{
2073
al2_endcmd();
2074
2075
if (!tabinfo)
2076
{ al2_continue("no information in table"); }
2077
2078
begintime = al0_clock();
2079
li = al0_compact();
2080
lj = al0_stdct();
2081
endtime = al0_clock();
2082
if (li)
2083
{ fprintf(fop, "CO"); }
2084
else
2085
{ fprintf(fop, "co"); }
2086
if (lj)
2087
{ fprintf(fop, "/ST"); }
2088
else
2089
{ fprintf(fop, "/st"); }
2090
fprintf(fop, ": a=%d r=%d h=%d n=%d; c=+%4.2f\n",
2091
nalive, knr, knh, nextdf, al0_diff(begintime,endtime));
2092
2093
continue;
2094
}
2095
2096
/* this stuff is done if the statistics package is included */
2097
2098
#ifdef AL0_STAT
2099
if (al2_match("stat[istics]") || al2_match("stats"))
2100
{
2101
al2_endcmd();
2102
STATDUMP;
2103
2104
continue;
2105
}
2106
#endif
2107
2108
if (al2_match("style"))
2109
{
2110
al2_endcmd();
2111
2112
if (rfactor1 < 0)
2113
{
2114
if (cfactor1 < 0)
2115
{ fprintf(fop, "style = R/C\n"); }
2116
else if (cfactor1 == 0)
2117
{ fprintf(fop, "style = R*\n"); }
2118
else
2119
{ fprintf(fop, "style = Cr\n"); }
2120
}
2121
else if (rfactor1 == 0)
2122
{
2123
if (cfactor1 < 0)
2124
{ fprintf(fop, "style = C* (aka C-style)\n"); }
2125
else if (cfactor1 == 0)
2126
{ fprintf(fop, "style = R/C (Rt & Ct values defaulted)\n"); }
2127
else
2128
{ fprintf(fop, "style = C\n"); }
2129
}
2130
else
2131
{
2132
if (cfactor1 < 0)
2133
{ fprintf(fop, "style = Rc\n"); }
2134
else if (cfactor1 == 0)
2135
{ fprintf(fop, "style = R\n"); }
2136
else
2137
{ fprintf(fop, "style = CR\n"); }
2138
}
2139
2140
continue;
2141
}
2142
2143
/* see comment for "enum[eration]" */
2144
2145
if (al2_match("subg[roup name]"))
2146
{
2147
al2_readname();
2148
al2_endcmd();
2149
2150
if (subgrpname != NULL)
2151
{ free(subgrpname); }
2152
subgrpname = NULL;
2153
subgrpname = al2_strdup(currname);
2154
2155
continue;
2156
}
2157
2158
/* Allows access to the system; ie, fires up a shell & passes it the
2159
(non-empty) argument. Use with caution, of course! The argument must
2160
consist of one line of printable characters (plus '\t'), excluding ';'.
2161
Trailing WS is removed. We do _no_ error checking on the call. */
2162
2163
if (al2_match("sys[tem]"))
2164
{
2165
al2_readname();
2166
al2_endcmd();
2167
2168
if (strlen(currname) == 0)
2169
{ al2_continue("empty argument"); }
2170
else
2171
{ system(currname); }
2172
2173
continue;
2174
}
2175
2176
if (al2_match("text"))
2177
{
2178
al2_readname();
2179
al2_endcmd();
2180
fprintf(fop, "%s\n", currname);
2181
2182
continue;
2183
}
2184
2185
if (al2_match("ti[me limit]"))
2186
{
2187
al2_readia();
2188
al2_endcmd();
2189
2190
if ( (intcnt > 0 && intarr[0] < -1) || intcnt > 1 )
2191
{ al2_continue("bad parameter"); }
2192
else if (intcnt == 0)
2193
{ fprintf(fop, "time limit = %d\n", tlimit); }
2194
else
2195
{ tlimit = intarr[0]; }
2196
2197
continue;
2198
}
2199
2200
/* The trace word command takes as arguments a coset number & a word.
2201
Unlike ACE2, we do not allow a multi-line word. */
2202
2203
if (al2_match("tw") || al2_match("trace[ word]"))
2204
{
2205
i = al2_readint();
2206
if (currip != ',')
2207
{ al2_continue("missing argument"); }
2208
al2_nextnw();
2209
if ((j = al2_pwrd(0)) == 0)
2210
{ al2_continue("empty argument"); }
2211
al2_endcmd();
2212
2213
if (!tabinfo)
2214
{ al2_continue("table d.n.e. or has no information"); }
2215
if (i < 1 || i >= nextdf || COL1(i) < 0)
2216
{ al2_continue("invalid/redundant coset number"); }
2217
2218
/* Now copy currword (gen'r nos) to currrep (col nos) */
2219
repsiz = 0;
2220
for (k = 0; k < j; k++)
2221
{
2222
if ( !al1_addrep( gencol[ndgen+currword[k]] ) )
2223
{ al2_continue("unable to build coset rep've"); }
2224
}
2225
2226
if ((k = al1_trrep(i)) == 0)
2227
{ fprintf(fop, "* Trace does not complete\n"); }
2228
else
2229
{ fprintf(fop, "%d * word = %d\n", i, k); }
2230
2231
continue;
2232
}
2233
2234
/* Negative workspace sizes are errors, zero size selects DEFWORK, and
2235
values <1K are rounded up to 1K. */
2236
2237
if (al2_match("wo[rkspace]"))
2238
{
2239
if ( !(isdigit(currip) || currip == '+' || currip == '-') )
2240
{
2241
al2_endcmd(); /* Error if currip not ';' or '\n'! */
2242
fprintf(fop, "workspace = %d x %d\n", workspace, workmult);
2243
}
2244
else
2245
{
2246
i = al2_readint();
2247
j = al2_readmult();
2248
al2_endcmd();
2249
2250
if (i < 0)
2251
{ al2_continue("argument must be non-negative"); }
2252
else if (i == 0) /* Use default value */
2253
{
2254
i = DEFWORK;
2255
j = 1;
2256
}
2257
else if (j == 1 && i < KILO) /* Minimum allowed is 1xKILO */
2258
{ i = KILO; }
2259
2260
workspace = i;
2261
workmult = j;
2262
2263
/* The casts to long are to allow 64-bit systems (ie, IP27/R10000)
2264
to break the 4G physical memory barrier. */
2265
2266
if (costable != NULL)
2267
{ free(costable); }
2268
costable =
2269
(int *)malloc((long)workspace*(long)workmult*(long)sizeof(int));
2270
if (costable == NULL)
2271
{
2272
okstart = okcont = okredo = FALSE; /* Problem, no table! */
2273
tabinfo = tabindex = FALSE;
2274
al2_restart("unable to resize workspace (will try default)");
2275
}
2276
2277
okstart = (ndgen > 0); /* New table ... */
2278
okcont = okredo = FALSE;
2279
tabinfo = tabindex = FALSE;
2280
}
2281
2282
continue;
2283
}
2284
2285
/* ... no match; signal an error */
2286
2287
al2_continue("there is no such keyword");
2288
}
2289
}
2290
2291
2292