GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
1/**************************************************************************23parser.c4Colin Ramsay ([email protected])52 Mar 0167ADVANCED COSET ENUMERATOR, Version 3.00189Copyright 200010Centre for Discrete Mathematics and Computing,11Department of Mathematics and12Department of Computer Science & Electrical Engineering,13The University of Queensland, QLD 4072.14(http://staff.itee.uq.edu.au/havas)1516Parser and dispatcher code for stand-alone ACE. We try to ensure that we17only change things in response to a command if the entire command is ok.18This means that the state is always consistent, and we can usually just19continue.2021Note: the al2_continue() routine is intended for cases where an `error'22does not effect the ability to continue, while al2_restart() is intended23for errors which (may) mean that continuing is not possible, so we have to24(re)start an enumeration. I'm not sure that I'm always careful in calling25the `right' one; we may have to tinker with this in the light of26experience.2728**************************************************************************/2930#include "al2.h"3132#include <ctype.h>33#include <string.h>3435int al2_pwrd(int); /* Forward declaration (parser is recursive) */3637/******************************************************************38void al2_readkey(void)3940Read a keyword into currkey[], converting it to LC. This removes41all leading WS, compresses middle WS to single ' ', and removes42trailing WS. It checks for bad characters and too short/long key,43and advances position to argument (if necessary). Note that44currkey has 64 posns (0..63), and we have to reserve one for the45string terminating '\0' character.46******************************************************************/4748void al2_readkey(void)49{50int i = 0;5152/* Copy the keyword into currkey[] */53while ( currip != ':' && currip != ';' && currip != '\n'54&& currip != '\r' && currip != EOF )55{56if (islower(currip))57{58if (i > 62)59{ al2_continue("keyword too long"); }60currkey[i++] = currip;61}62else if (isupper(currip))63{64if (i > 62)65{ al2_continue("keyword too long"); }66currkey[i++] = tolower(currip);67}68else if (currip == ' ' || currip == '\t')69{70if (i > 0 && currkey[i-1] != ' ') /* leading/multiple spaces? */71{72if (i > 63) /* may be removable trailing space */73{ al2_continue("keyword too long"); }74currkey[i++] = ' ';75}76}77else78{ al2_continue("keywords must only contain letters"); }79al2_nextip();80}8182if (i > 0 && currkey[i-1] == ' ') /* remove trailing space */83{ i--; }84currkey[i] = '\0'; /* string terminator */8586if (i == 0)87{ al2_continue("empty keyword"); }8889if (currip == ':') /* skip any following ':' & WS */90{ al2_nextnw(); }91}9293/******************************************************************94void al2_readname(void)9596Read a `name' (ie, command argument). Used for group/subgroup97names/descriptions, I/O filenames, and system calls. There is only98one of these (a fixed length <128 global), so we may need to take a99copy if it'll be required later. Note that currip has been setup100to point to a non-blank char (ie, either the first char of the101string or an end-of-command char). Note that we strip trailing102spaces & tabs from the name, for `neatness'. We assume ASCII.103******************************************************************/104105void al2_readname(void)106{107int i = 0;108109while ( currip != ';' && currip != '\n' && currip != '\r' &&110currip != EOF )111{112if (!((currip >= ' ' && currip <= '~') || (currip == '\t')))113{ al2_continue("string contains invalid character"); }114if (i > 126) /* 0..126 is data, 127 is '\0' */115{ al2_continue("string too long"); }116117currname[i++] = currip;118al2_nextip();119}120121while (i > 0 && (currname[i-1] == ' ' || currname[i-1] == '\t'))122{ i--; }123currname[i] = '\0';124}125126/******************************************************************127int al2_readmult(void)128129Reads the multiplier for the workspace size, if we recognise it.130******************************************************************/131132int al2_readmult(void)133{134int u = 1; /* Default is x1 */135136if (currip == 'k' || currip == 'K')137{138u = KILO;139al2_nextnw();140}141else if (currip == 'm' || currip == 'M')142{143u = MEGA;144al2_nextnw();145}146else if (currip == 'g' || currip == 'G')147{148u = GIGA;149al2_nextnw();150}151152return u;153}154155/******************************************************************156int al2_readgen(void)157158Reads in a (possibly comma separated) list of generator letters.159These are stored (in lower case) in the order they're read in the160currname array. Duplicates are verboten and the number of161generators read is returned. Currip is guaranteed to be a letter,162so j > 0 on return is certain (in the absence of errors).163******************************************************************/164165int al2_readgen(void)166{167int i, j = 0;168169while ( currip != ';' && currip != '\n' && currip != '\r' &&170currip != EOF )171{172if (islower(currip))173{174for (i = 1; i <= j; i++)175{176if (currname[i] == currip)177{ al2_continue("duplicated generator"); }178}179currname[++j] = currip;180}181else182{ al2_continue("generators are letters between 'a' & 'z'"); }183184al2_nextnw();185if (currip == ',')186{ al2_nextnw(); }187}188189return(j);190}191192/******************************************************************193Logic al2_match(char *pattern)194195Test whether currkey can be matched to pattern.196******************************************************************/197198Logic al2_match(char *pattern)199{200int i;201202/* first try to match the required part */203for (i = 0; pattern[i] != '\0' && pattern[i] != '['; i++)204{205if (pattern[i] != currkey[i])206{ return FALSE; }207}208209/* if the rest is optional, try to match it */210if (pattern[i] == '[')211{212for ( ; pattern[i+1] != '\0' && pattern[i+1] != ']'; i++)213{214if (pattern[i+1] != currkey[i])215{ return (currkey[i] == '\0'); }216}217}218219/* everything matched, but the keyword should not be longer */220return (currkey[i] == '\0');221}222223/******************************************************************224void al2_endcmd(void)225226To terminate a command, we must see a ';' or a newline.227******************************************************************/228229void al2_endcmd(void)230{231if (currip != ';' && currip != '\n' && currip != '\r' && currip != EOF)232{ al2_continue("command must be terminated by ';' or <newline>"); }233}234235/******************************************************************236int al2_readuint(void)237238Read in an unsigned integer239******************************************************************/240241int al2_readuint(void)242{243int u = 0;244245if (isdigit(currip))246{247while (isdigit(currip))248{249u = 10*u + (currip - '0');250al2_nextip();251}252al2_skipws();253}254else255{ al2_continue("number must begin with digit"); }256257return(u);258}259260/******************************************************************261int al2_readint(void)262263Read in a (possibly signed) integer264******************************************************************/265266int al2_readint(void)267{268if (isdigit(currip))269{ return(al2_readuint()); }270else if (currip == '+')271{272al2_nextnw();273return(al2_readuint());274}275else if (currip == '-')276{277al2_nextnw();278return(-al2_readuint());279}280else281{ al2_continue("number must begin with digit or '+' or '-'"); }282283return(-1); /* Stops compiler warning; never get here! */284}285286/******************************************************************287void al2_readia(void)288289Read comma-separated list of <= 32 integers into the integer array.290******************************************************************/291292void al2_readia(void)293{294intcnt = 0;295296if ( !(isdigit(currip) || currip == '+' || currip == '-') )297{ return; } /* list is empty */298299intarr[intcnt++] = al2_readint();300while (currip == ',')301{302if (intcnt == 32)303{ al2_continue("too many integers in sequence"); }304305al2_nextnw();306intarr[intcnt++] = al2_readint();307}308}309310/**************************************************************************311The functions from hereon, until al2_cmdloop(), are responsible for312implementing the recursive-descent parser. The current word is built-up in313currword, and when this has been done successfully it is added to a temp314list of words. If an error occurs, then this list will be `valid'; it will315contain all words up to, but not including, the one in error. Currently316this list is accessed via a pointer in the `top-level' function _rdwl() or317_rdrl(). This pointer should really be made a global, so that we could318attempt error-recovery or free up the space it uses (currently, errors may319cause memory leakage). A successful call to either of the top-level320functions returns a new list, which should be used to replace the current321list of either group relators or subgroup generators. It is the caller's322(of the parser) responsibility to deallocate any replaced list.323**************************************************************************/324325/******************************************************************326void al2_addgen(int pos, int gen)327328Add a generator to the current word, growing the word as necessary.329******************************************************************/330331void al2_addgen(int pos, int gen)332{333if (currword == NULL)334{335currsiz = 16;336if ((currword = (int *)malloc(currsiz*sizeof(int))) == NULL)337{ al2_continue("out of memory (initial word)"); }338}339else if (pos >= currsiz) /* valid entries are [0] .. [currsiz-1] */340{341currsiz *= 2;342if ((currword = (int *)realloc(currword, currsiz*sizeof(int))) == NULL)343{ al2_continue("out of memory (adding generator)"); }344}345346currword[pos] = gen;347}348349/******************************************************************350void al2_addwrd(int dst, int src, int len)351352Add a word to the current word. Note that this is used to copy353from currword to itself, so either dst <= src or dst >= src+len.354******************************************************************/355356void al2_addwrd(int dst, int src, int len)357{358int i;359360for (i = 0; i < len; i++)361{ al2_addgen(dst+i, currword[src+i]); }362}363364/******************************************************************365void al2_invwrd(int pos, int len)366367Sneakily invert a subword of the current word. Note that we have368to reverse the order _and_ invert all entries. So we have to touch369all posns; hence some of the apparently unnecessary work.370******************************************************************/371372void al2_invwrd(int pos, int len)373{374int i, gen1, gen2;375376for (i = 1; i <= (len+1)/2; i++)377{378gen1 = currword[pos + i-1];379gen2 = currword[pos + len-i];380381currword[pos + i-1] = -gen2;382currword[pos + len-i] = -gen1;383}384}385386/******************************************************************387Wlelt *al2_newwrd(int len)388389Make a new word-list element, and copy the first len values from390currword into it. Note that currword is indexed from 0, while data391in the list is indexed from 1! At this stage all words are fully392expanded, and have exponent 1. However, we need to flag those393words which were _entered_ as involutions (ie, as x^2, not xx).394******************************************************************/395396Wlelt *al2_newwrd(int len)397{398Wlelt *p;399int i;400401if ((p = al1_newelt()) == NULL)402{ al2_restart("no memory for new word-list element"); }403if ((p->word = (int *)malloc((len+1)*sizeof(int))) == NULL)404{ al2_restart("no memory for word-list element data"); }405406for (i = 1; i <= len; i++)407{ p->word[i] = currword[i-1]; }408p->len = len;409p->exp = 1;410411if (len == 2 && currword[0] == currword[1] && currexp == 2)412{ p->invol = TRUE; }413else414{ p->invol = FALSE; }415416return(p);417}418419/******************************************************************420int al2_pelt(int beg)421422Parses an element into currword, beginning at position beg, and423returns the length of the parsed element. The BNF for an element:424425<element> = <generator> ["'"]426| "(" <word> { "," <word> } ")" ["'"]427| "[" <word> { "," <word> } "]" ["'"]428429Note that (a,b) is parsed as [a,b], but (ab) as ab. Also, [a,b,c]430is parsed as [[a,b],c].431******************************************************************/432433int al2_pelt(int beg)434{435int len, len2, gen, sign;436char ch;437438if (isalpha(currip)) /* we have 'a'..'z' or 'A'..'Z' */439{440if (!galpha)441{ al2_restart("you specified numeric generators"); }442443if (islower(currip))444{445ch = currip;446sign = 1;447}448else449{450ch = tolower(currip);451sign = -1;452}453al2_nextnw();454455gen = genal[ch-'a'+1];456if (gen == 0)457{ al2_restart("<letter> must be one of the generator letters"); }458al2_addgen(beg, sign*gen);459len = 1;460}461else if (isdigit(currip) || currip == '+' || currip == '-')462{ /* parse a numeric generator */463if (galpha)464{ al2_restart("you specified alphabetic generators"); }465466sign = 1;467if (currip == '+')468{469al2_nextnw();470if (!isdigit(currip))471{ al2_restart("'+' must be followed by generator number"); }472}473else if (currip == '-')474{475al2_nextnw();476if (!isdigit(currip))477{ al2_restart("'-' must be followed by generator number"); }478sign = -1;479}480481gen = al2_readuint();482if (gen == 0 || gen > ndgen)483{ al2_restart("<number> must be one of the generator numbers"); }484al2_addgen(beg, sign*gen);485len = 1;486}487else if (currip == '(' || currip == '[')488{ /* parse parenthesised word / commutator */489ch = currip;490al2_nextnw();491len = al2_pwrd(beg);492493while (currip == ',')494{495al2_nextnw();496len2 = al2_pwrd(beg+len);497al2_addwrd(beg+len+len2, beg, len+len2);498al2_invwrd(beg, len);499al2_invwrd(beg+len, len2);500len = 2*(len + len2);501}502503if (ch == '(' && currip != ')')504{ al2_restart("'(' must have a matching ')'"); }505if (ch == '[' && currip != ']')506{ al2_restart("'[' must have a matching ']'"); }507al2_nextnw();508}509else /* otherwise this is an error */510{511al2_restart("<word> must begin with a <generator>, a '(' or a '['");512}513514/* A "'" inverts the current element. "''" is not allowed. */515516if (currip == '\'')517{518al2_invwrd(beg, len);519al2_nextnw();520}521522return len; /* return the length */523}524525/******************************************************************526int al2_pfact(int beg)527528Parses a factor into currword, beginning at position beg, and529returns the length of the parsed factor. The BNF for a factor:530531<factor> = <element> [ ["^"] <integer> | "^" <element> ]532533Note that if alphabetic generators are used then the exponentiation534"^" can be dropped (but not the conjugation "^"), and the exponent535"-1" can be abbreviated to "-". So "a^-1 b" can be written as536"a^-1b", "a-1b", "a^-b", or "a-b".537538******************************************************************/539540int al2_pfact(int beg)541{542int len, len2, i;543544len = al2_pelt(beg); /* parse (first) element */545546if ( currip == '^' ||547(galpha && (isdigit(currip) || currip == '+' || currip == '-')) )548{549if (currip == '^') /* strip away the '^' */550{ al2_nextnw(); }551552if (isdigit(currip) || currip == '-' || currip == '+')553{554if (currip == '+')555{556al2_nextnw();557if (!galpha && !isdigit(currip))558{ al2_restart("'+' must be followed by exponent number"); }559}560else if (currip == '-')561{562al2_invwrd(beg, len);563al2_nextnw();564if (!galpha && !isdigit(currip))565{ al2_restart("'-' must be followed by exponent number"); }566}567568/* If we're using alphabetic generators & dropping the "^", then569"a^-1" can be coded as "a-", so we might not have a digit here.570We'll fall through, using the element as already parsed! */571572if (isdigit(currip))573{574currexp = al2_readuint();575for (i = 2; i <= currexp; i++)576{ al2_addwrd(beg + (i-1)*len, beg, len); }577len = len*currexp;578}579}580else if (isalpha(currip) || currip == '(' || currip == '[')581{582/* This is sneaky! */583584len2 = al2_pelt(beg+len);585al2_addwrd(beg+len+len2, beg+len, len2);586al2_invwrd(beg, len);587al2_invwrd(beg, len+len2);588len = len2 + len + len2;589}590else591{ al2_restart("'^' must be followed by exponent or element"); }592}593594return len;595}596597/******************************************************************598int al2_pwrd(int beg)599600Parses a word into currword starting at position beg. Words are601defined by the following BNF:602603<word> = <factor> { "*" | "/" <factor> }604605The "*" can be dropped everywhere; but of course two numeric606generators, or a numeric exponent and a numeric generator, must be607separated by a whitespace.608609We use currexp to help detect when a relator/generator of the form610x^2/X^2 (or one of its variants) has been entered. At the _start_611of every word we prime it to 1.612******************************************************************/613614int al2_pwrd(int beg)615{616int len, len2;617char ch;618619if (beg == 0)620{ currexp = 1; }621622len = al2_pfact(beg);623624while ( currip == '*' || currip == '/' || isalpha(currip) ||625isdigit(currip) || currip == '+' || currip == '-' ||626currip == '(' || currip == '[' )627{628if (currip == '*')629{630ch = '*';631al2_nextnw();632}633else if (currip == '/')634{635ch = '/';636al2_nextnw();637}638else639{ ch = '*'; }640641len2 = al2_pfact(beg+len);642if (ch == '/')643{ al2_invwrd(beg+len, len2); }644len += len2;645}646647return len;648}649650/******************************************************************651Wlelt *al2_rdwrd(void)652653This parses a word into currword, copies it into a properly setup654new word-list element, and returns a pointer to it.655******************************************************************/656657Wlelt *al2_rdwrd(void)658{ return(al2_newwrd(al2_pwrd(0))); }659660/******************************************************************661void al2_pawrd(Wlist *p)662663Parse a word and add it to the list of words.664******************************************************************/665666void al2_pawrd(Wlist *p)667{ al1_addwl(p, al2_rdwrd()); }668669/******************************************************************670Wlist *al2_rdwl(void)671672Reads and returns a list of words.673******************************************************************/674675Wlist *al2_rdwl(void)676{677Wlist *p;678679if ((p = al1_newwl()) == NULL) /* allocate a new list of words */680{ al2_continue("unable to create new word-list"); }681682if (currip != ';') /* parse a sequence of words */683{684al2_pawrd(p);685while (currip == ',')686{687al2_nextnw();688al2_pawrd(p);689}690}691692return(p); /* return the list of words */693}694695/******************************************************************696void al2_parel(Wlist *l)697698Note that W1 = W2 = W3 becomes W1W2' & W1W3'!699******************************************************************/700701void al2_parel(Wlist *l)702{703int len1, len2;704705len1 = al2_pwrd(0); /* parse left hand side word */706707len2 = 0;708while (currip == '=') /* parse a sequence of right-hand sides */709{710al2_nextnw();711len2 = al2_pwrd(len1);712al2_invwrd(len1, len2);713al1_addwl(l, al2_newwrd(len1+len2));714}715716if (len2 == 0) /* no RH side, take LH side as relator */717{ al1_addwl(l, al2_newwrd(len1)); }718}719720/******************************************************************721Wlist *al2_rdrl(void)722723Reads and returns a list of relators. Note that this is _not_ the724same as a list of words (ie, subgroup generators) since we're725allowed things like W1 = W2. So we have to invoke the parser via726the parse relator function _parel().727******************************************************************/728729Wlist *al2_rdrl(void)730{731Wlist *p;732733if ((p = al1_newwl()) == NULL) /* allocate a new list of words */734{ al2_continue("unable to create new word-list"); }735736if (currip != ';')737{738al2_parel(p);739while (currip == ',')740{741al2_nextnw();742al2_parel(p);743}744}745746return(p);747}748749/******************************************************************750void al2_cmdloop(void)751******************************************************************/752753void al2_cmdloop(void)754{755int i,j,k;756Wlist *p;757Logic f, li, lj;758759while (TRUE)760{761/* Do the necessary for the next command (or end-of-file). Note that762the next command may follow on the same line, or we may have to skip763over a '\n' to the next line. (Not sure if this is bomb-proof under764all (error) conditions.) */765766al2_nextnw();767skipnl = TRUE;768al2_skipws();769skipnl = FALSE;770771if (currip == EOF)772{ break; }773774al2_readkey();775776/* The work-horse; just plow through until the first match, do it,777and then skip to the end of the while(). */778779if (al2_match("add gen[erators]") || al2_match("sg"))780{781if (ndgen < 1)782{ al2_continue("there are no generators as yet"); }783784skipnl = TRUE;785al2_skipws();786787p = al2_rdwl();788al2_endcmd();789790if (genlst == NULL)791{ genlst = p; }792else793{ al1_concatwl(genlst,p); }794795nsgpg = genlst->len;796797okcont = FALSE;798tabinfo = tabindex = FALSE;799800continue;801}802803if (al2_match("add rel[ators]") || al2_match("rl"))804{805if (ndgen < 1)806{ al2_continue("there are no generators as yet"); }807808skipnl = TRUE;809al2_skipws();810811p = al2_rdrl();812al2_endcmd();813814if (rellst == NULL)815{ rellst = p; }816else817{ al1_concatwl(rellst,p); }818819ndrel = rellst->len;820821okcont = FALSE;822tabindex = FALSE;823824continue;825}826827/* All Equivalent Presentations */828829if (al2_match("aep"))830{831al2_readia();832al2_endcmd();833834if (intcnt != 1)835{ al2_continue("bad number of parameters"); }836if (intarr[0] < 1 || intarr[0] > 7)837{ al2_continue("invalid first argument"); }838839if (!okstart)840{ al2_continue("can't start (no generators/workspace)"); }841if (rellst == NULL || rellst->len == 0)842{ al2_continue("can't start (no relators)"); }843844al2_aep(intarr[0]);845846continue;847}848849if (al2_match("ai") || al2_match("alter i[nput]"))850{851al2_readname();852al2_endcmd();853854if (strlen(currname) == 0)855{ strcpy(currname, "stdin"); }856al2_aip(currname);857858continue;859}860861if (al2_match("ao") || al2_match("alter o[utput]"))862{863al2_readname();864al2_endcmd();865866if (strlen(currname) == 0)867{ strcpy(currname, "stdout"); }868al2_aop(currname);869870continue;871}872873/* What to do with asis in continue/redo? It's (current) value in a874printout may not match that actually used at the start of a run, when875the involutary generators are picked up & the columns allocated, and876these settings are frozen until the next start/begin/end! */877878if (al2_match("as[is]"))879{880al2_readia();881al2_endcmd();882883if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )884{ al2_continue("bad parameter"); }885else if (intcnt == 0)886{ fprintf(fop, "asis = %s\n", asis ? "true" : "false"); }887else888{ asis = (intarr[0] == 1); }889890continue;891}892893if (al2_match("beg[in]") || al2_match("end") || al2_match("start"))894{895al2_endcmd();896897if (!okstart)898{ al2_continue("can't start (no generators?)"); }899900al1_rslt(lresult = al1_start(0));901902/* If something `sensible' happened, then it'll be ok to continue or903redo this run. If not, then we make sure that we must begin a new904run. Note that here (& in continue/redo) we play it safe by905enforcing a new run, even if there may be no need to. Note that the906SG phase is 1st in start mode, so should _always_ be done. */907908if (lresult > 0 && sgdone) /* finite index */909{910okcont = okredo = TRUE;911tabinfo = tabindex = TRUE;912}913else if (lresult >= -259 && sgdone) /* holey/overflow/limit */914{915okcont = okredo = TRUE;916tabinfo = TRUE;917tabindex = FALSE;918}919else /* SG overflow/`error' */920{921okcont = okredo = FALSE;922tabinfo = tabindex = FALSE;923}924925continue;926}927928if (al2_match("bye") || al2_match("exit") || al2_match("q[uit]"))929{930al2_endcmd();931932break;933}934935if (al2_match("cc") || al2_match("coset coinc[idence]"))936{937al2_readia();938al2_endcmd();939940if (intcnt != 1)941{ al2_continue("bad number of parameters"); }942if (!tabinfo)943{ al2_continue("there is no table information"); }944if (intarr[0] < 2 || intarr[0] >= nextdf || COL1(intarr[0]) < 0)945{ al2_continue("invalid/redundant coset number"); }946947al2_cc(intarr[0]);948949continue;950}951952if (al2_match("c[factor]") || al2_match("ct[ factor]"))953{954al2_readia();955al2_endcmd();956957if (intcnt > 1)958{ al2_continue("bad parameter"); }959else if (intcnt == 0)960{ fprintf(fop, "ct factor = %d\n", cfactor1); }961else962{ cfactor1 = intarr[0]; }963964continue;965}966967/* See comments for "begin". */968969if (al2_match("check") || al2_match("redo"))970{971al2_endcmd();972973if (!okredo)974{ al2_continue("can't redo (different presentation?)"); }975976al1_rslt(lresult = al1_start(2));977978if (lresult > 0 && sgdone)979{980okcont = TRUE;981tabinfo = tabindex = TRUE;982}983else if (lresult >= -259 && sgdone)984{985okcont = TRUE;986tabinfo = TRUE;987tabindex = FALSE;988}989else990{991okcont = FALSE;992tabinfo = tabindex = FALSE;993}994if (lresult < -260)995{ okredo = FALSE; }996997continue;998}9991000if (al2_match("com[paction]"))1001{1002al2_readia();1003al2_endcmd();10041005if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 100)) ||1006intcnt > 1 )1007{ al2_continue("bad parameter"); }1008else if (intcnt == 0)1009{ fprintf(fop, "compaction = %d\n", comppc); }1010else1011{ comppc = intarr[0]; }10121013continue;1014}10151016/* See comments for "begin". */10171018if (al2_match("con[tinue]"))1019{1020al2_endcmd();10211022if (!okcont)1023{ al2_continue("can't continue (altered presentation?)"); }10241025al1_rslt(lresult = al1_start(1));10261027if (lresult > 0 && sgdone)1028{ tabinfo = tabindex = TRUE; }1029else if (lresult >= -259 && sgdone)1030{1031tabinfo = TRUE;1032tabindex = FALSE;1033}1034else1035{1036okcont = FALSE;1037tabinfo = tabindex = FALSE;1038}10391040continue;1041}10421043if (al2_match("cy[cles]"))1044{1045al2_endcmd();10461047if (!tabindex)1048{ al2_continue("there is no completed table"); }10491050begintime = al0_clock();1051li = al0_compact();1052endtime = al0_clock();1053if (li)1054{ fprintf(fop, "CO"); }1055else1056{ fprintf(fop, "co"); }1057fprintf(fop, ": a=%d r=%d h=%d n=%d; c=+%4.2f\n",1058nalive, knr, knh, nextdf, al0_diff(begintime,endtime));10591060al2_cycles();10611062continue;1063}10641065if (al2_match("ded mo[de]") || al2_match("dmod[e]"))1066{1067al2_readia();1068al2_endcmd();10691070if (intcnt == 0)1071{ fprintf(fop, "deduction mode = %d\n", dedmode); }1072else if (intcnt == 1)1073{1074if (intarr[0] < 0 || intarr[0] > 4)1075{ al2_continue("bad mode parameter"); }1076dedmode = intarr[0];1077}1078else1079{ al2_continue("bad parameter count"); }10801081continue;1082}10831084if (al2_match("ded si[ze]") || al2_match("dsiz[e]"))1085{1086al2_readia();1087al2_endcmd();10881089if ( (intcnt > 0 && intarr[0] < 0) || intcnt > 1 )1090{ al2_continue("bad parameter"); }1091else if (intcnt == 0)1092{ fprintf(fop, "deduction stack = %d\n", dedsiz1); }1093else1094{ dedsiz1 = intarr[0]; }10951096continue;1097}10981099if (al2_match("def[ault]"))1100{1101al2_endcmd();11021103cfactor1 = 0;1104comppc = 10;1105dedmode = 4;1106dedsiz1 = 1000;1107ffactor1 = 0;1108lahead = 0;1109mendel = FALSE;1110nrinsgp1 = -1;1111pdefn = 3;1112pdsiz1 = 256;1113rfactor1 = 0;1114rfill = TRUE;1115pcomp = FALSE;11161117continue;1118}11191120if (al2_match("del gen[erators]") || al2_match("ds"))1121{1122al2_readia();1123al2_endcmd();11241125if (intcnt < 1 || genlst == NULL || genlst->len < 1)1126{ al2_continue("empty argument list / generator list"); }1127al2_dw(genlst);1128nsgpg = genlst->len;11291130okcont = okredo = FALSE;1131tabinfo = tabindex = FALSE;11321133continue;1134}11351136if (al2_match("del rel[ators]") || al2_match("dr"))1137{1138al2_readia();1139al2_endcmd();11401141if (intcnt < 1 || rellst == NULL || rellst->len < 1)1142{ al2_continue("empty argument list / relator list"); }1143al2_dw(rellst);1144ndrel = rellst->len;11451146okcont = okredo = FALSE;1147tabinfo = tabindex = FALSE;11481149continue;1150}11511152if (al2_match("d[ump]"))1153{1154al2_readia();1155al2_endcmd();11561157if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 2)) ||1158(intcnt > 1 && (intarr[1] < 0 || intarr[1] > 1)) ||1159intcnt > 2 )1160{ al2_continue("bad parameters"); }1161else if (intcnt == 0)1162{ al0_dump(FALSE); }1163else if (intcnt == 1)1164{1165if (intarr[0] == 0)1166{ al0_dump(FALSE); }1167else if (intarr[0] == 1)1168{ al1_dump(FALSE); }1169else1170{ al2_dump(FALSE); }1171}1172else1173{1174if (intarr[0] == 0)1175{ al0_dump(intarr[1] == 1); }1176else if (intarr[0] == 1)1177{ al1_dump(intarr[1] == 1); }1178else1179{ al2_dump(intarr[1] == 1); }1180}11811182continue;1183}11841185if (al2_match("easy"))1186{1187al2_endcmd();11881189cfactor1 = 0;1190comppc = 100;1191dedmode = 0;1192dedsiz1 = 1000;1193ffactor1 = 1;1194lahead = 0;1195mendel = FALSE;1196nrinsgp1 = 0;1197pdefn = 0;1198pdsiz1 = 256;1199rfactor1 = 1000;1200rfill = TRUE;1201pcomp = FALSE;12021203continue;1204}12051206if (al2_match("echo"))1207{1208al2_readia();1209al2_endcmd();12101211if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )1212{ al2_continue("bad parameter"); }1213else if (intcnt == 0)1214{ fprintf(fop, "echo = %s\n", echo ? "true" : "false"); }1215else1216{ echo = (intarr[0] == 1); }12171218continue;1219}12201221/* Note that it is ok to set the name to "". If the call to _strdup()1222fails, then _continue() will be invoked. This could leave grpname1223still pointing to freed storage, hence the explicit setting to NULL. */12241225if (al2_match("enum[eration]") || al2_match("group name"))1226{1227al2_readname();1228al2_endcmd();12291230if (grpname != NULL)1231{ free(grpname); }1232grpname = NULL;1233grpname = al2_strdup(currname);12341235continue;1236}12371238if (al2_match("fel[sch]"))1239{1240al2_readia();1241al2_endcmd();12421243if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )1244{ al2_continue("bad parameter"); }12451246if (intcnt == 1 && intarr[0] == 1) /* `Enhanced' Felsch */1247{1248ffactor1 = 0;1249nrinsgp1 = -1;1250pdefn = 3;1251}1252else /* Felsch (~ Pure C) */1253{1254ffactor1 = 1;1255nrinsgp1 = 0;1256pdefn = 0;1257}12581259cfactor1 = 1000;1260comppc = 10;1261dedmode = 4;1262dedsiz1 = 1000;1263lahead = 0;1264mendel = FALSE;1265pdsiz1 = 256;1266rfactor1 = 0;1267rfill = FALSE;1268pcomp = FALSE;12691270continue;1271}12721273/* If you set this to 0, Level 1 will set ffactor to a `sensible'1274default (eg, 5(ncol+2)/4). */12751276if (al2_match("f[factor]") || al2_match("fi[ll factor]"))1277{1278al2_readia();1279al2_endcmd();12801281if ( (intcnt > 0 && intarr[0] < 0) || intcnt > 1 )1282{ al2_continue("bad parameter"); }1283else if (intcnt == 0)1284{ fprintf(fop, "fill factor = %d\n", ffactor1); }1285else1286{ ffactor1 = intarr[0]; }12871288continue;1289}12901291if (al2_match("gen[erators]") || al2_match("subgroup gen[erators]"))1292{1293if (ndgen < 1)1294{ al2_continue("there are no generators as yet"); }12951296skipnl = TRUE;1297al2_skipws();12981299p = al2_rdwl();1300al2_endcmd();13011302if (genlst != NULL)1303{ al1_emptywl(genlst); free(genlst); }1304genlst = p;1305nsgpg = p->len;13061307okcont = okredo = FALSE;1308tabinfo = tabindex = FALSE;13091310continue;1311}13121313if (al2_match("gr[oup generators]"))1314{1315if (isdigit(currip) || currip == '+' || currip == '-')1316{1317i = al2_readint();1318al2_endcmd();1319if (i < 1)1320{ al2_continue("bad parameter"); }13211322ndgen = i;1323galpha = FALSE;13241325okstart = (costable != NULL);1326okcont = okredo = FALSE;1327tabinfo = tabindex = FALSE;13281329/* The current relator & generator lists are now invalid */13301331if (rellst != NULL)1332{ al1_emptywl(rellst); free(rellst); }1333rellst = NULL;1334ndrel = 0;1335if (genlst != NULL)1336{ al1_emptywl(genlst); free(genlst); }1337genlst = NULL;1338nsgpg = 0;1339}1340else if (isalpha(currip))1341{1342i = al2_readgen();1343al2_endcmd();13441345ndgen = i;1346galpha = TRUE;1347for (j = 1; j <= ndgen; j++)1348{ algen[j] = currname[j]; }1349algen[ndgen+1] = '\0'; /* &algen[1] is printable string */13501351for (j = 1; j <= 26; j++)1352{ genal[j] = 0;}1353for (j = 1; j <= ndgen; j++)1354{ genal[algen[j]-'a'+1] = j; }13551356okstart = (costable != NULL);1357okcont = okredo = FALSE;1358tabinfo = tabindex = FALSE;13591360if (rellst != NULL)1361{ al1_emptywl(rellst); free(rellst); }1362rellst = NULL;1363ndrel = 0;1364if (genlst != NULL)1365{ al1_emptywl(genlst); free(genlst); }1366genlst = NULL;1367nsgpg = 0;1368}1369else1370{1371al2_endcmd();13721373fprintf(fop, "group generators = ");1374if (ndgen < 1)1375{ fprintf(fop, "none\n"); }1376else if (galpha)1377{1378for (i = 1; i <= ndgen; i++)1379{ fprintf(fop, "%c", algen[i]); }1380fprintf(fop, "\n");1381}1382else1383{ fprintf(fop, "1..%d\n", ndgen); }1384}13851386continue;1387}13881389if (al2_match("group relators") || al2_match("rel[ators]"))1390{1391if (ndgen < 1)1392{ al2_continue("there are no generators as yet"); }13931394skipnl = TRUE;1395al2_skipws();13961397p = al2_rdrl();1398al2_endcmd();13991400if (rellst != NULL)1401{ al1_emptywl(rellst); free(rellst); }1402rellst = p;1403ndrel = p->len;14041405okcont = okredo = FALSE;1406tabinfo = tabindex = FALSE;14071408continue;1409}14101411if (al2_match("hard"))1412{1413al2_endcmd();14141415cfactor1 = 1000;1416comppc = 10;1417dedmode = 4;1418dedsiz1 = 1000;1419ffactor1 = 0;1420lahead = 0;1421mendel = FALSE;1422nrinsgp1 = -1;1423pdefn = 3;1424pdsiz1 = 256;1425rfactor1 = 1;1426rfill = TRUE;1427pcomp = FALSE;14281429continue;1430}14311432if (al2_match("h[elp]"))1433{1434al2_endcmd();1435al2_help();14361437continue;1438}14391440if (al2_match("hlt"))1441{1442al2_endcmd();14431444cfactor1 = 0;1445comppc = 10;1446dedmode = 0;1447dedsiz1 = 1000;1448ffactor1 = 1;1449lahead = 1;1450mendel = FALSE;1451nrinsgp1 = 0;1452pdefn = 0;1453pdsiz1 = 256;1454rfactor1 = 1000;1455rfill = TRUE;1456pcomp = FALSE;14571458continue;1459}14601461if (al2_match("ho[le limit]"))1462{1463al2_readia();1464al2_endcmd();14651466if ( (intcnt > 0 && (intarr[0] < -1 || intarr[0] > 100)) ||1467intcnt > 1 )1468{ al2_continue("bad parameter"); }1469else if (intcnt == 0)1470{ fprintf(fop, "hole limit = %d\n", hlimit); }1471else1472{ hlimit = intarr[0]; }14731474continue;1475}14761477if (al2_match("look[ahead]"))1478{1479al2_readia();1480al2_endcmd();14811482if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 4)) || intcnt > 1 )1483{ al2_continue("bad parameter"); }1484else if (intcnt == 0)1485{ fprintf(fop, "lookahead = %d\n", lahead); }1486else1487{ lahead = intarr[0]; }14881489continue;1490}14911492if (al2_match("loop[ limit]"))1493{1494al2_readia();1495al2_endcmd();14961497if ( (intcnt > 0 && intarr[0] < 0) || intcnt > 1 )1498{ al2_continue("bad parameter"); }1499else if (intcnt == 0)1500{ fprintf(fop, "loop limit = %d\n", llimit); }1501else1502{ llimit = intarr[0]; }15031504continue;1505}15061507if (al2_match("max[ cosets]"))1508{1509al2_readia();1510al2_endcmd();15111512if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] == 1)) ||1513intcnt > 1 )1514{ al2_continue("bad parameter"); }1515else if (intcnt == 0)1516{ fprintf(fop, "max cosets = %d\n", maxrow1); }1517else1518{ maxrow1 = intarr[0]; }15191520continue;1521}15221523if (al2_match("mess[ages]") || al2_match("mon[itor]"))1524{1525al2_readia();1526al2_endcmd();15271528if (intcnt > 1)1529{ al2_continue("too many parameters"); }1530else if (intcnt == 0)1531{1532if (msgctrl)1533{1534if (msghol)1535{ fprintf(fop, "messages = %d (+ holes)\n", msgincr); }1536else1537{ fprintf(fop, "messages = %d (- holes)\n", msgincr); }1538}1539else1540{ fprintf(fop, "messages = off\n"); }1541}1542else if (intarr[0] == 0)1543{1544msgctrl = FALSE;1545msghol = FALSE;1546msgincr = 0;1547}1548else if (intarr[0] < 0)1549{1550msgctrl = TRUE;1551msghol = TRUE;1552msgincr = -intarr[0];1553}1554else1555{1556msgctrl = TRUE;1557msghol = FALSE;1558msgincr = intarr[0];1559}15601561continue;1562}15631564if (al2_match("mend[elsohn]"))1565{1566al2_readia();1567al2_endcmd();15681569if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )1570{ al2_continue("bad parameter"); }1571else if (intcnt == 0)1572{ fprintf(fop, "mendelsohn = %s\n", mendel ? "true" : "false"); }1573else1574{ mendel = (intarr[0] == 1); }15751576continue;1577}15781579if (al2_match("mo[de]"))1580{1581al2_endcmd();15821583if (okstart)1584{ fprintf(fop, "start = yes,"); }1585else1586{ fprintf(fop, "start = no,"); }1587if (okcont)1588{ fprintf(fop, " continue = yes,"); }1589else1590{ fprintf(fop, " continue = no,"); }1591if (okredo)1592{ fprintf(fop, " redo = yes\n"); }1593else1594{ fprintf(fop, " redo = no\n"); }15951596continue;1597}15981599if (al2_match("nc") || al2_match("normal[ closure]"))1600{1601al2_readia();1602al2_endcmd();16031604if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )1605{ al2_continue("bad parameter"); }1606if (!tabinfo)1607{ al2_continue("there is no table information"); }16081609begintime = al0_clock();1610li = al0_compact();1611endtime = al0_clock();1612if (li)1613{ fprintf(fop, "CO"); }1614else1615{ fprintf(fop, "co"); }1616fprintf(fop, ": a=%d r=%d h=%d n=%d; c=+%4.2f\n",1617nalive, knr, knh, nextdf, al0_diff(begintime,endtime));16181619if (intcnt == 0)1620{ al2_normcl(FALSE); }1621else1622{ al2_normcl(intarr[0] == 1); }16231624continue;1625}16261627if (al2_match("no[ relators in subgroup]"))1628{1629al2_readia();1630al2_endcmd();16311632if ( (intcnt > 0 && intarr[0] < -1) || intcnt > 1 )1633{ al2_continue("bad parameter"); }1634else if (intcnt == 0)1635{ fprintf(fop, "no. rels in subgr = %d\n", nrinsgp1); }1636else1637{ nrinsgp1 = intarr[0]; }16381639continue;1640}16411642if (al2_match("oo") || al2_match("order[ option]"))1643{1644al2_readia();1645al2_endcmd();16461647if (intcnt != 1)1648{ al2_continue("missing argument / too many arguments"); }1649if (!tabinfo)1650{ al2_continue("no information in table"); }16511652al2_oo(intarr[0]);16531654continue;1655}16561657if (al2_match("opt[ions]"))1658{1659al2_endcmd();1660al2_opt();16611662continue;1663}16641665/* an old command, which we quietly ignore */16661667if (al2_match("par[ameters]"))1668{1669al2_endcmd();1670continue;1671}16721673if (al2_match("path[ compression]"))1674{1675al2_readia();1676al2_endcmd();16771678if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )1679{ al2_continue("bad parameter"); }1680else if (intcnt == 0)1681{ fprintf(fop, "path compression = %s\n", pcomp ? "on" : "off"); }1682else1683{ pcomp = (intarr[0] == 1); }16841685continue;1686}16871688if (al2_match("pd mo[de]") || al2_match("pmod[e]"))1689{1690al2_readia();1691al2_endcmd();16921693if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 3)) || intcnt > 1 )1694{ al2_continue("bad parameter"); }1695else if (intcnt == 0)1696{ fprintf(fop, "pref. definition mode = %d\n", pdefn); }1697else1698{ pdefn = intarr[0]; }16991700continue;1701}17021703if (al2_match("pd si[ze]") || al2_match("psiz[e]"))1704{1705al2_readia();1706al2_endcmd();17071708if ( (intcnt > 0 && intarr[0] < 0) || intcnt > 1 )1709{ al2_continue("bad parameter"); }1710else if (intcnt == 0)1711{ fprintf(fop, "pref. definition list = %d\n", pdsiz1); }1712else if (intarr[0] == 0)1713{ pdsiz1 = intarr[0]; } /* use default value */1714else if (intarr[0]%2 == 1)1715{ al2_continue("bad parameter"); } /* odd (incl. 1) */1716else1717{ /* even parameter, >= 2 */1718i = intarr[0];1719while (i%2 == 0)1720{ i /= 2; }1721if (i == 1)1722{ pdsiz1 = intarr[0]; }1723else1724{ al2_continue("bad parameter"); } /* not power of 2 */1725}17261727continue;1728}17291730if (al2_match("print det[ails]") || al2_match("sr"))1731{1732al2_readia();1733al2_endcmd();17341735if ((intcnt > 0 && (intarr[0] < 0 || intarr[0] > 5)) || intcnt > 1)1736{ al2_continue("bad parameter"); }1737else if (intcnt == 0)1738{ al1_prtdetails(0); }1739else1740{ al1_prtdetails(intarr[0]); }17411742continue;1743}17441745/* Negative first parameter means include order/rep, else don't. No1746parameters means all the table, one parameter "x" means (1,x,1), two1747parameters "x,y" means (x,y,1), and three parameters "x,y,z" means1748(x,y,z). Note the compulsory compaction, to prevent utterly confusing1749the user! (This may cause disded to become true.) */17501751if (al2_match("pr[int table]"))1752{1753al2_readia();1754al2_endcmd();17551756if (!tabinfo)1757{ al2_continue("no information in table"); }17581759if (intcnt == 0)1760{1761f = FALSE;1762intarr[0] = 1;1763intarr[1] = nextdf-1;1764intarr[2] = 1;1765}1766else if (intcnt <= 3)1767{1768if (intarr[0] < 0)1769{1770f = TRUE;1771intarr[0] = -intarr[0];1772}1773else1774{ f = FALSE; }1775}1776else1777{ al2_continue("too many parameters"); }17781779if (intcnt == 1)1780{1781intarr[1] = intarr[0];1782intarr[0] = intarr[2] = 1;1783}1784else if (intcnt == 2)1785{ intarr[2] = 1; }17861787if (intarr[0] >= nextdf)1788{ intarr[0] = nextdf-1; }1789if (intarr[1] >= nextdf)1790{ intarr[1] = nextdf-1; }17911792if (intarr[0] < 1 || intarr[1] < intarr[0] || intarr[2] < 1 )1793{ al2_continue("bad parameters"); }17941795begintime = al0_clock();1796li = al0_compact();1797endtime = al0_clock();1798if (li)1799{ fprintf(fop, "CO"); }1800else1801{ fprintf(fop, "co"); }1802fprintf(fop, ": a=%d r=%d h=%d n=%d; c=+%4.2f\n",1803nalive, knr, knh, nextdf, al0_diff(begintime,endtime));18041805al1_prtct(intarr[0], intarr[1], intarr[2], FALSE, f);18061807continue;1808}18091810if (al2_match("pure c[t]"))1811{1812al2_endcmd();18131814cfactor1 = 1000;1815comppc = 100;1816dedmode = 4;1817dedsiz1 = 1000;1818ffactor1 = 1;1819lahead = 0;1820mendel = FALSE;1821nrinsgp1 = 0;1822pdefn = 0;1823pdsiz1 = 256;1824rfactor1 = 0;1825rfill = FALSE;1826pcomp = FALSE;18271828continue;1829}18301831if (al2_match("pure r[t]"))1832{1833al2_endcmd();18341835cfactor1 = 0;1836comppc = 100;1837dedmode = 0;1838dedsiz1 = 1000;1839ffactor1 = 1;1840lahead = 0;1841mendel = FALSE;1842nrinsgp1 = 0;1843pdefn = 0;1844pdsiz1 = 256;1845rfactor1 = 1000;1846rfill = FALSE;1847pcomp = FALSE;18481849continue;1850}18511852/* This is a `dangerous' option, since it can go wrong, or `corrupt'1853the status, in so many ways. We try to minimise problems by being1854very strict as to when we allow it to be called. How much of this is1855necessary/desirable is moot. */18561857if (al2_match("rc") || al2_match("random coinc[idences]"))1858{1859al2_readia();1860al2_endcmd();18611862if (intcnt < 1 || intcnt > 2)1863{ al2_continue("bad number of parameters"); }1864if (intarr[0] < 0)1865{ al2_continue("invalid first argument"); }1866if (intcnt == 2 && intarr[1] < 1)1867{ al2_continue("invalid second argument"); }18681869if (!tabinfo)1870{ al2_continue("there is no table information"); }1871if (!okredo)1872{ al2_continue("can't redo (different presentation?)"); }18731874if (lresult == 1)1875{ al2_continue("trivial finite index already exists"); }18761877if (intarr[0] == 0)1878{1879if (lresult > 0)1880{ al2_continue("non-trivial finite index already present"); }1881}1882else1883{1884if (lresult > 0 && lresult < intarr[0])1885{ al2_continue("finite index already < argument"); }1886if (lresult > 0 && lresult%intarr[0] == 0)1887{ al2_continue("finite index already multiple of argument"); }1888}18891890if (intarr[0] >= nalive)1891{ al2_continue("not enough active cosets available"); }18921893if (intcnt == 1) /* Try 8 times, by default */1894{ al2_rc(intarr[0],8); }1895else1896{ al2_rc(intarr[0],intarr[1]); }18971898continue;1899}19001901if (al2_match("rec[over]") || al2_match("contig[uous]"))1902{1903if (!tabinfo)1904{ al2_continue("there is no table information"); }19051906begintime = al0_clock();1907li = al0_compact();1908endtime = al0_clock();1909if (li)1910{ fprintf(fop, "CO"); }1911else1912{ fprintf(fop, "co"); }1913fprintf(fop, ": a=%d r=%d h=%d n=%d; c=+%4.2f\n",1914nalive, knr, knh, nextdf, al0_diff(begintime,endtime));19151916continue;1917}19181919/* Random Equivalent Presentations */19201921if (al2_match("rep"))1922{1923al2_readia();1924al2_endcmd();19251926if (intcnt < 1 || intcnt > 2)1927{ al2_continue("bad number of parameters"); }1928if (intarr[0] < 1 || intarr[0] > 7)1929{ al2_continue("invalid first argument"); }1930if (intcnt == 2 && intarr[1] < 1)1931{ al2_continue("invalid second argument"); }19321933if (!okstart)1934{ al2_continue("can't start (no generators/workspace)"); }1935if (rellst == NULL || rellst->len == 0)1936{ al2_continue("can't start (no relators)"); }19371938if (intcnt == 1)1939{ al2_rep(intarr[0], 8); }1940else1941{ al2_rep(intarr[0], intarr[1]); }19421943continue;1944}19451946/* an old command, which we quietly ignore */19471948if (al2_match("restart"))1949{1950al2_endcmd();1951continue;1952}19531954if (al2_match("r[factor]") || al2_match("rt[ factor]"))1955{1956al2_readia();1957al2_endcmd();19581959if (intcnt > 1)1960{ al2_continue("bad parameter"); }1961else if (intcnt == 0)1962{ fprintf(fop, "rt factor = %d\n", rfactor1); }1963else1964{ rfactor1 = intarr[0]; }19651966continue;1967}19681969if (al2_match("row[ filling]"))1970{1971al2_readia();1972al2_endcmd();19731974if ( (intcnt > 0 && (intarr[0] < 0 || intarr[0] > 1)) || intcnt > 1 )1975{ al2_continue("bad parameter"); }1976else if (intcnt == 0)1977{ fprintf(fop, "row fill = %s\n", rfill ? "on" : "off"); }1978else1979{ rfill = (intarr[0] == 1); }19801981continue;1982}19831984if (al2_match("sc") || al2_match("stabil[ising cosets]"))1985{1986al2_readia();1987al2_endcmd();19881989if (intcnt != 1)1990{ al2_continue("missing argument / too many arguments"); }1991if (!tabinfo)1992{ al2_continue("no information in table"); }19931994al2_sc(intarr[0]);19951996continue;1997}19981999/* We emulate, as best we can, the odd-numbered enumeration strategies2000given in Table 5.5.1 (p. 245) of C.C. Sims' book. The even-numbered2001ones involve `standardise-as-you-go', which we don't do; however we can2002standardise the table once we're done, or we can pause an enumeration2003at any time, standardise, and then continue. (This last is not as daft2004as it seems and does, in fact, sometimes prove beneficial.) The2005strategies are: 1) HLT, no save; 3) HLT, save; 5) CHLT, no save; 7)2006CHLT, save; 9) Felsch (save). */20072008if (al2_match("sims"))2009{2010al2_readia();2011al2_endcmd();20122013if ( intcnt != 1 ||2014intarr[0] < 1 || intarr[0] > 9 || intarr[0]%2 == 0 )2015{ al2_continue("bad parameter"); }20162017switch(intarr[0])2018{2019case 1: /* cf. "pure r" + row-fill */2020cfactor1 = 0;2021dedmode = 0;2022mendel = FALSE;2023rfactor1 = 1000;2024rfill = TRUE;2025break;2026case 3:2027cfactor1 = 0;2028dedmode = 4;2029mendel = FALSE;2030rfactor1 = -1000;2031rfill = TRUE;2032break;2033case 5:2034cfactor1 = 0;2035dedmode = 0;2036mendel = TRUE;2037rfactor1 = 1000;2038rfill = TRUE;2039break;2040case 7:2041cfactor1 = 0;2042dedmode = 4;2043mendel = TRUE;2044rfactor1 = -1000;2045rfill = TRUE;2046break;2047case 9: /* cf. "pure c" / "Felsch" */2048cfactor1 = 1000;2049dedmode = 4;2050mendel = FALSE;2051rfactor1 = 0;2052rfill = FALSE;2053break;2054}20552056/* These parameters are common to all modes. */20572058comppc = 10; /* compaction always allowed */2059dedsiz1 = 1000; /* default (starting) size */2060ffactor1 = 1; /* fill-factor not active */2061lahead = 0; /* never lookahead */2062nrinsgp1 = 0; /* no (active) RS phase */2063pdefn = 0; /* no preferred/immediate defns ... */2064pdsiz1 = 256;2065pcomp = FALSE;20662067continue;2068}20692070if (al2_match("st[andard table]"))2071{2072al2_endcmd();20732074if (!tabinfo)2075{ al2_continue("no information in table"); }20762077begintime = al0_clock();2078li = al0_compact();2079lj = al0_stdct();2080endtime = al0_clock();2081if (li)2082{ fprintf(fop, "CO"); }2083else2084{ fprintf(fop, "co"); }2085if (lj)2086{ fprintf(fop, "/ST"); }2087else2088{ fprintf(fop, "/st"); }2089fprintf(fop, ": a=%d r=%d h=%d n=%d; c=+%4.2f\n",2090nalive, knr, knh, nextdf, al0_diff(begintime,endtime));20912092continue;2093}20942095/* this stuff is done if the statistics package is included */20962097#ifdef AL0_STAT2098if (al2_match("stat[istics]") || al2_match("stats"))2099{2100al2_endcmd();2101STATDUMP;21022103continue;2104}2105#endif21062107if (al2_match("style"))2108{2109al2_endcmd();21102111if (rfactor1 < 0)2112{2113if (cfactor1 < 0)2114{ fprintf(fop, "style = R/C\n"); }2115else if (cfactor1 == 0)2116{ fprintf(fop, "style = R*\n"); }2117else2118{ fprintf(fop, "style = Cr\n"); }2119}2120else if (rfactor1 == 0)2121{2122if (cfactor1 < 0)2123{ fprintf(fop, "style = C* (aka C-style)\n"); }2124else if (cfactor1 == 0)2125{ fprintf(fop, "style = R/C (Rt & Ct values defaulted)\n"); }2126else2127{ fprintf(fop, "style = C\n"); }2128}2129else2130{2131if (cfactor1 < 0)2132{ fprintf(fop, "style = Rc\n"); }2133else if (cfactor1 == 0)2134{ fprintf(fop, "style = R\n"); }2135else2136{ fprintf(fop, "style = CR\n"); }2137}21382139continue;2140}21412142/* see comment for "enum[eration]" */21432144if (al2_match("subg[roup name]"))2145{2146al2_readname();2147al2_endcmd();21482149if (subgrpname != NULL)2150{ free(subgrpname); }2151subgrpname = NULL;2152subgrpname = al2_strdup(currname);21532154continue;2155}21562157/* Allows access to the system; ie, fires up a shell & passes it the2158(non-empty) argument. Use with caution, of course! The argument must2159consist of one line of printable characters (plus '\t'), excluding ';'.2160Trailing WS is removed. We do _no_ error checking on the call. */21612162if (al2_match("sys[tem]"))2163{2164al2_readname();2165al2_endcmd();21662167if (strlen(currname) == 0)2168{ al2_continue("empty argument"); }2169else2170{ system(currname); }21712172continue;2173}21742175if (al2_match("text"))2176{2177al2_readname();2178al2_endcmd();2179fprintf(fop, "%s\n", currname);21802181continue;2182}21832184if (al2_match("ti[me limit]"))2185{2186al2_readia();2187al2_endcmd();21882189if ( (intcnt > 0 && intarr[0] < -1) || intcnt > 1 )2190{ al2_continue("bad parameter"); }2191else if (intcnt == 0)2192{ fprintf(fop, "time limit = %d\n", tlimit); }2193else2194{ tlimit = intarr[0]; }21952196continue;2197}21982199/* The trace word command takes as arguments a coset number & a word.2200Unlike ACE2, we do not allow a multi-line word. */22012202if (al2_match("tw") || al2_match("trace[ word]"))2203{2204i = al2_readint();2205if (currip != ',')2206{ al2_continue("missing argument"); }2207al2_nextnw();2208if ((j = al2_pwrd(0)) == 0)2209{ al2_continue("empty argument"); }2210al2_endcmd();22112212if (!tabinfo)2213{ al2_continue("table d.n.e. or has no information"); }2214if (i < 1 || i >= nextdf || COL1(i) < 0)2215{ al2_continue("invalid/redundant coset number"); }22162217/* Now copy currword (gen'r nos) to currrep (col nos) */2218repsiz = 0;2219for (k = 0; k < j; k++)2220{2221if ( !al1_addrep( gencol[ndgen+currword[k]] ) )2222{ al2_continue("unable to build coset rep've"); }2223}22242225if ((k = al1_trrep(i)) == 0)2226{ fprintf(fop, "* Trace does not complete\n"); }2227else2228{ fprintf(fop, "%d * word = %d\n", i, k); }22292230continue;2231}22322233/* Negative workspace sizes are errors, zero size selects DEFWORK, and2234values <1K are rounded up to 1K. */22352236if (al2_match("wo[rkspace]"))2237{2238if ( !(isdigit(currip) || currip == '+' || currip == '-') )2239{2240al2_endcmd(); /* Error if currip not ';' or '\n'! */2241fprintf(fop, "workspace = %d x %d\n", workspace, workmult);2242}2243else2244{2245i = al2_readint();2246j = al2_readmult();2247al2_endcmd();22482249if (i < 0)2250{ al2_continue("argument must be non-negative"); }2251else if (i == 0) /* Use default value */2252{2253i = DEFWORK;2254j = 1;2255}2256else if (j == 1 && i < KILO) /* Minimum allowed is 1xKILO */2257{ i = KILO; }22582259workspace = i;2260workmult = j;22612262/* The casts to long are to allow 64-bit systems (ie, IP27/R10000)2263to break the 4G physical memory barrier. */22642265if (costable != NULL)2266{ free(costable); }2267costable =2268(int *)malloc((long)workspace*(long)workmult*(long)sizeof(int));2269if (costable == NULL)2270{2271okstart = okcont = okredo = FALSE; /* Problem, no table! */2272tabinfo = tabindex = FALSE;2273al2_restart("unable to resize workspace (will try default)");2274}22752276okstart = (ndgen > 0); /* New table ... */2277okcont = okredo = FALSE;2278tabinfo = tabindex = FALSE;2279}22802281continue;2282}22832284/* ... no match; signal an error */22852286al2_continue("there is no such keyword");2287}2288}2289229022912292