Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  presentation.c   Sprache: C

 
/****************************************************************************
**
**    presentation.c          Presentation                     Werner Nickel
**                                         nickel@mathematik.tu-darmstadt.de
*/



#include "config.h"

#include "presentation.h"
#include "pcarith.h"

static node *Word(void);


/*
**    ------------------------ GENERAL PURPOSE -------------------------
**    The first part of this file just contain some auxiliary functions.
*/



/*
**    FreeNode() recursively frees a given node.
*/

void    FreeNode(node *n) {
 if (n->type != TGEN && n->type != TNUM) {
  FreeNode(n->cont.op.l);
  FreeNode(n->cont.op.r);
 }
 Free(n);
}

/*
**    GetNode() allocates space for a node of given type.
*/

static node    *GetNode(EvalType type) {
 node    *n;

 n = (node *)Allocate(sizeof(node));
 n->type = type;

 return n;
}

/*
**    GenNumber() maintains the array GenNames[] of generator names which
**    have been read so far. GenNumber() is called from the parser in order
**    to create a new generator or to look up an existing one. The generator
**    name is communicated to GenNumber() through the variable gname.
**
**    If GenNumber() is called with the flag CREATE it checks if the generator
**    name in gname has not occurred before and, if not, creates a new entry
**    and returns the new generator number. If the name had occurred before
**    the illegal generator number 0 is returned.
**
**    If GenNumber() is called with the flag NOCREATE it searches for the
**    generator name and returns the corresponding number if a matching entry
**    in GenNames[] is found. If no matching entry is found, the illegal
**    generator number 0 is returned.
*/

static char     **GenNames;
static unsigned NrGens = 0;

#define NOCREATE 0
#define CREATE   1

static gen GenNumber(char *gname, int status) {
 unsigned        i;

 if (status == CREATE && NrGens == 0)  /* Initialize GenNames[]. */
  GenNames = (char **)Allocate(128 * sizeof(char*));

 for (i = 1; i <= NrGens; i++)  /* Find the generator name. */
  if (strcmp(gname, GenNames[i]) == 0) {
   if (status == CREATE) return (gen)0;
   return (gen)i;
  }

 /* It's a new generator. */
 if (status == NOCREATE) return (gen)0;
 NrGens++;
 if (NrGens % 128 == 0)
  GenNames = (char **)ReAllocate((void *)GenNames,
                                 (NrGens + 128) * sizeof(char *));

 i = strlen(gname);
 GenNames[ NrGens ] = (char *)Allocate((i + 1) * sizeof(char));
 strcpy(GenNames[NrGens], gname);

 return NrGens;
}

/*
**    GenName() is the inverse function for GenNumber(). It returns the
**    name of a generator given by its number.
*/

const char *GenName(gen g) {
 if (g > (gen)NrGens)
  return 0;
 return GenNames[g];
}

/*
**    ------------------------- SCANNER ---------------------------
**    The second part of this file contains the scanner. The parser
**    starts after the function Generator().
*/


/*
**    The following macros define tokens.
*/

typedef enum {
 LPAREN,
 RPAREN,
 LBRACK,
 RBRACK,
 LBRACE,
 RBRACE,

 MULT,
 POWER,
 EQUAL,
 DEQUALL,
 DEQUALR,

 PLUS,
 MINUS,

 LANGLE,
 RANGLE,

 PIPE,
 COMMA,
 SEMICOLON,
 NUMBER,
 GEN
} TokenType;

static int      Ch;             /* Contains the next char on the input. */
static TokenType Token;          /* Contains the current token. */
static int      Line;           /* Current line number. */
static int      TLine;          /* Line number where token starts. */
static int      Char;           /* Current character number. */
static int      TChar;          /* Character number where token starts. */
static const char     *InFileName;    /* Current input file name. */
static const char     *OutFileName;   /* Current output file name. */
static FILE     *InFp;          /* Current input file pointer. */
static FILE     *OutFp;         /* Current output file pointer. */
static int      N;              /* Contains the integer just read. */
static char     Gen[128];       /* Contains the generator name. */
/*
static const char     *TokenName[] = {
"", "LParen", "RParen", "LBrack", "RBrack", "LBrace",
"RBrace", "Mult",   "Power",  "Equal",  "DEqualL",
"DEqualR", "Plus",   "Minus",  "LAngle", "RAngle",
"Pipe",   "Comma",  "Number", "Gen"
};
*/


/*
**    SyntaxError() just prints a syntax error and the line and place
**    where is occurred and then exits.
**    No recovery from syntax errors :-)
*/

static void SyntaxError(const char *str) {
 if (str == 0)
  fprintf(stderr, "%s, line %d, char %d.\n",
          InFileName, TLine, TChar);
 else
  fprintf(stderr, "%s, line %d, char %d: %s.\n",
          InFileName, TLine, TChar, str);

 exit(1);
}

/*
**    ReadCh() reads the next character from the current input file.
**    At the same time it checks for lines terminated with '\'. Such
**    a line is continued in the next line, therefore ReadCh() discards
**    '\' and the following '\n'.
*/

static void ReadCh(void) {

 Ch = getc(InFp);
 Char++;
 if (Ch == '\\') {
  Ch = getc(InFp);
  if (Ch == '\n') { Line++; Char = 0; ReadCh(); }
  else             { ungetc(Ch, InFp); Ch = '\\'; }
 }
}

/*
**    SkipBlanks() skips the characters ' ', '\t' and '\n' as well as
**    comments. A comment starts with '#' and finishes at the end of
**    the line.
*/

static void     SkipBlanks(void) {

 /* If Ch is empty, the next character is fetched. */
 if (Ch == '\0') ReadCh();

 /* First blank characters and comments are skipped. */
 while (Ch == ' ' || Ch == '\t' || Ch == '\n' || Ch == '#') {
  if (Ch == '#') {  /* Skip to the end of line. */
   while (Ch != '\n') ReadCh();
  }
  if (Ch == '\n') { Line++; Char = 0; }
  ReadCh();
 }
}

/*
**    Number reads a number from the input.
*/

static void Number(void) {

 unsigned int    m, n = 0, overflow = 0;

 while (isdigit(Ch)) {
  m = n;
  n = 10 * n + (Ch - '0');
  if ((n - (Ch - '0')) / 10 != m) { overflow = 1; break; }
  ReadCh();
 }

 if (overflow) {
  fprintf(stderr, "Integer overflow reading %u%c", m, Ch);
  ReadCh();
  while (isdigit(Ch)) { fprintf(stderr, "%c", Ch); ReadCh(); }
  fprintf(stderr, " in\n");
  SyntaxError((char *)0);
 } else if (n >= (1U << (8 * sizeof(unsigned int) - 1))) {
  fprintf(stderr, "Integer overflow reading %u in\n", n);
  SyntaxError((char *)0);
 }

 N = n;
}

/*
**    Generator() reads characters from the input stream until a non-
**    alphanumeric character is encountered. Only the first 127 characters
**    are significant as generator name and are copied into the global
**    array Gen[]. All other characters are discarded.
*/

static void     Generator(void) {

 int     i;

 for (i = 0; i < 127 && (isalnum(Ch) || Ch == '_' || Ch == '.'); i++) {
  Gen[i] = Ch;
  ReadCh();
 }
 Gen[i] = '\0';
 /* Discard the rest. */
 while (isalnum(Ch) || Ch == '_' || Ch == '.') ReadCh();
}

/*
**    NextToken reads the next token from the input stream. It first
**    skips all the blank characters and comments.
*/

static void NextToken(void) {
 SkipBlanks();
 TChar = Char;
 TLine = Line;
 switch (Ch) {
 case '(':
 { Token = LPAREN; ReadCh(); break; }
 case ')':
 { Token = RPAREN; ReadCh(); break; }
 case '[':
 { Token = LBRACK; ReadCh(); break; }
 case ']':
 { Token = RBRACK; ReadCh(); break; }
 case '{':
 { Token = LBRACE; ReadCh(); break; }
 case '}':
 { Token = RBRACE; ReadCh(); break; }

 case '*':
 { Token = MULT;   ReadCh(); break; }
 case '^':
 { Token = POWER;  ReadCh(); break; }
 case ':': {
  ReadCh();
  if (Ch != '=') SyntaxError("illegal character");
  Token = DEQUALL;
  ReadCh();
  break;
 }
 case '=': {
  ReadCh();
  if (Ch != ':') Token = EQUAL;
  else { Token = DEQUALR; ReadCh(); }
  break;
 }

 case '+':
 { Token = PLUS;   ReadCh(); break; }
 case '-':
 { Token = MINUS;  ReadCh(); break; }

 case '<':
 { Token = LANGLE; ReadCh(); break; }
 case '>':
 { Token = RANGLE; ReadCh(); break; }

 case '|':
 { Token = PIPE;      ReadCh(); break; }
 case ',':
 { Token = COMMA;     ReadCh(); break; }
 case ';':
 { Token = SEMICOLON; ReadCh(); break; }

 case '0':
 case '1' :
 case '2' :
 case '3' :
 case '4' :
 case '5':
 case '6' :
 case '7' :
 case '8' :
 case '9' :
 { Token = NUMBER; Number(); break; }
 default :
  if (isalnum(Ch) || Ch == '_' || Ch == '.')
  { Token = GEN; Generator(); break; }
  else SyntaxError("illegal character");
 }
 /*      printf( "# NextToken(): %s\n", TokenName[Token] );*/
}

/*
**    ------------------------- PARSER ----------------------------
**    Here the third part of this file starts containing the parser.
**
**    This is the grammar that defines the syntax of a finite presentation.
**    Quoted items (except 'empty') are recognized by the scanner and returned
**    as so called tokens. The unquoted symbol | indicates alternatives.
**
**    presentation: '<' genlist '|' rellist '>' |
**                  '<' genlist ; genlist '|' rellist '>'
**
**    genlist:         'empty' | genseq
**    genseq:          'generator' | 'generator' ',' genseq
**
**    rellist:         'empty' | relseq
**    relseq:          relation | relation ',' relseq
**
**    relation:        word | word '=' word | word '=:' word | word ':=' word
**
**    word:            power | power '*' word
**
**    power:           atom '^' atom | atom '^' snumber | atom
**
**    atom:            'generator' | '(' word ')' | commutator
**
**    commutator:      '[' word ',' wordseq ']'
**    wordseq          word | word ',' wordseq
**
**    snumber:         'sign' 'number' | 'number'
*/


/*
**    InitParser() does exactly what the name suggests.
*/

static void InitParser(FILE *fp, const char *filename) {
 InFp = fp;
 InFileName = filename;

 Ch = '\0';
 Char = 0;
 Line = 1;

 NextToken();
}

/*
**    Snumber() reads a signed number. The defining rule is:
**
**    snumber:         '+' 'number' | '-' 'number' | 'number'
*/

static node     *Snumber(void) {

 node    *n = 0;

 if (Token == NUMBER) {
  n = GetNode(TNUM);
  n->cont.n = N;
  NextToken();
 } else if (Token == PLUS) {
  NextToken();
  if (Token != NUMBER) SyntaxError("Number expected");
  n = GetNode(TNUM);
  n->cont.n = N;
  NextToken();
 } else if (Token == MINUS) {
  NextToken();
  if (Token != NUMBER) SyntaxError("Number expected");
  n = GetNode(TNUM);
  n->cont.n = -N;
  NextToken();
 } else SyntaxError("Number expected");

 return n;
}

/*
**    The defining rules for commutators are:
**
**    commutator:      '[' word ',' wordseq ']'
**                   | '[' word ',' 'number' word ]
**    wordseq          word | word ',' wordseq
**
**    A word starts either with 'generator', with '(' or with '['.
*/

static node     *Commutator(void) {

 node            *n, *o;

 if (Token != LBRACK)
  SyntaxError("Left square bracket expected");

 NextToken();
 if (Token != GEN && Token != LPAREN && Token != LBRACK)
  SyntaxError("Word expected");

 o = Word();
 if (Token != COMMA) SyntaxError("Comma expected");
 while (Token == COMMA) {
  NextToken();
  if (Token != GEN && Token != NUMBER &&
          Token != LPAREN && Token != LBRACK)
   SyntaxError("Word expected");

  if (Token == NUMBER) {
   /* An Engel relation is on the input stream. */
   n = GetNode(TENGEL);
   n->cont.op.l = o;

   if (N <= 0) SyntaxError("Engel-n must be positive");

   n->cont.op.e = GetNode(TNUM);
   n->cont.op.e->cont.n = N;
   NextToken();

   n->cont.op.r = Word();
   break;
  } else {
   n = GetNode(TCOMM);
   n->cont.op.l = o;
   n->cont.op.r = Word();
   o = n;
  }
 }
 if (Token != RBRACK) SyntaxError("Right square bracket missing");
 NextToken();
 return n;
}

/*
**    Atom() reads an atom. Note that Atom() creates a generator by
**    calling GenNumber().
**
**    The defining rule for atoms is:
**
**    atom:            'generator' | '(' word ')' | commutator
*/

static node     *Atom(void) {

 node            *n = 0;

 if (Token == GEN) {
  n = GetNode(TGEN);
  n->cont.g = GenNumber(Gen, NOCREATE);
  if (n->cont.g == (gen)0) SyntaxError("Unknown generator");
  NextToken();
 } else if (Token == LPAREN) {
  NextToken();
  n = Word();
  if (Token != RPAREN)
   SyntaxError("Closing parenthesis expected");
  NextToken();
 } else if (Token == LBRACK) {
  n = Commutator();
 } else {
  SyntaxError("Generator, left parenthesis or commutator expected");
 }
 return n;
}

/*
**    Power() reads a power. The defining rule is:
**
**    power:           atom | atom '^' atom | atom '^' snumber |
**
*/

static node     *Power_(void) {

 node    *n, *o;

 o = Atom();
 if (Token == POWER) {
  NextToken();
  if (Token == PLUS || Token == MINUS || Token == NUMBER) {
   n = o;
   o = GetNode(TPOW);
   o->cont.op.l = n;
   o->cont.op.r = Snumber();
  } else {
   n = o;
   o = GetNode(TCONJ);
   o->cont.op.l = n;
   o->cont.op.r = Atom();
  }
 }
 return o;
}

/*
**    Word() reads a word. The defining rule is:
**
**    word:            power | power '*' word
**
**    A word starts either with 'generator', with '(' or with '['.
*/

static node *Word(void) {

 node    *n, *o;

 o = Power_();
 if (Token == MULT) {
  NextToken();
  n = o;
  o = GetNode(TMULT);
  o->cont.op.l = n;
  o->cont.op.r = Word();
 }

 return o;
}

/*
**    Relation() reads a relation. The defining rule is:
**
**    relation:        word | word '=' word | word '=:' word | word ':=' word
**
**    A relation starts either with 'generator', with '(' or with '['.
*/

static node     *Relation(void) {

 node    *n, *o;

 if (Token != GEN && Token != LPAREN && Token != LBRACK)
  SyntaxError("relation expected");

 o = Word();
 if (Token == EQUAL) {
  NextToken();
  n = o;
  o = GetNode(TREL);
  o->cont.op.l = n;
  o->cont.op.r = Word();
 } else if (Token == DEQUALL) {
  NextToken();
  n = o;
  o = GetNode(TDRELL);
  o->cont.op.l = n;
  o->cont.op.r = Word();
 } else if (Token == DEQUALR) {
  NextToken();
  n = o;
  o = GetNode(TDRELR);
  o->cont.op.l = n;
  o->cont.op.r = Word();
 }

 return o;
}

/*
**    RelList() reads a list of relations. The defining rules are:
**
**    rellist:         'empty' | relseq
**    relseq:          relation | relation ',' relseq
**
**    A relation starts either with 'generator', with '(' or with '['.
*/

static node     **RelList(void) {

 node     **rellist;
 unsigned n = 0;

 rellist = (node **)Allocate(sizeof(node *));
 rellist[0] = (node *)0;
 if (Token != GEN && Token != LPAREN && Token != LBRACK)
  return rellist;

 rellist = (node**)ReAllocate((void *)rellist, 2 * sizeof(node *));
 rellist[n++] = Relation();
 while (Token == COMMA) {
  NextToken();
  rellist = (node**)ReAllocate((void *)rellist, (n + 2) * sizeof(node *));
  rellist[n++] = Relation();
 }
 rellist[n] = (node *)0;

 return rellist;
}

/*
**    GenList() reads a list of generators.  The list of generators may
**    consist of abstract generators and identical generators.  Identical
**    generators are used to specify identical relations.
**
**    The defining rules are:
**
**    genlist:         'empty' | genseq | genseq ; genseq
**    genseq:          'generator' | 'generator' ',' genseq
*/

static int      GenList(void) {

 int     nrgens = 0;

 if (Token != GEN) return nrgens;

 nrgens++;
 if (GenNumber(Gen, CREATE) == (gen)0)
  SyntaxError("Duplicate generator");
 NextToken();
 while (Token == COMMA) {
  NextToken();
  if (Token != GEN) SyntaxError("Generator expected");
  nrgens++;
  if (GenNumber(Gen, CREATE) == (gen)0)
   SyntaxError("Duplicate generator");
  NextToken();
 }

 return nrgens;
}

/*
**    The following data structure holds a presentation.
*/

struct  pres {
 unsigned nragens;      /* number of abstract generators  */
 unsigned nrigens;      /* number of identical generators */
 unsigned nrrels;       /* number of relations            */
 node     **rels;       /* pointer to relations           */
};

static  struct pres Pres;

/*
**    NumberOfAbstractGens() returns the number of abstract generators.
*/

int     NumberOfAbstractGens(void) { return Pres.nragens; }

/*
**    NumberOfIdenticalGens() returns the number of identical generators.
*/

int     NumberOfIdenticalGens(void) { return Pres.nrigens; }

/*
**    NumberOfGens() returns the number of abstract and identical generators.
*/

int     NumberOfGens(void) { return Pres.nragens + Pres.nrigens; }

/*
**    NumberOfRels() returns the number of relations.
*/

int     NumberOfRels(void) { return Pres.nrrels; }

/*
**    NextRelation() returns the next relation, if it exists,
**    and returns the null pointer otherwise.
**    FirstRelation initializes the variable NextRel and calls
**    NextRelation().
**    NthRelation() returns the n-th relation, if n is in the
**    range [0..NumberOfRels()-1] and the null pointer otherwise.
**    CurrentRelation() returns the relation just being processed.
*/

static  int     NextRel;
node    *NextRelation(void) {

 if (NextRel >= NumberOfRels()) return (node *)0;

 return Pres.rels[NextRel++];
}

node    *FirstRelation(void) {

 NextRel = 0;
 return NextRelation();
}

node    *NthRelation(int n) {
 if (n < 0 || n >= NumberOfRels()) return (node *)0;

 return Pres.rels[n];
}

node    *CurrentRelation(void) { return Pres.rels[NextRel - 1]; }

/*
**    Presentation reads a finite presentation. The syntax of a presentation
**    is:
**        presentation: '<' genlist '|' rellist '>' |
**                      '<' genlist ; genlist '|' rellist '>'
*/

void    Presentation(FILE *fp, const char *filename) {
 InitParser(fp, filename);

 if (Token != LANGLE) SyntaxError("presentation expected");
 NextToken();

 if (Token != GEN && Token != PIPE)
  SyntaxError("generator or vertical bar expected");

 Pres.nragens = GenList();

 if (Token == SEMICOLON) {
  NextToken();
  Pres.nrigens = GenList();
 } else
  Pres.nrigens = 0;

 if (Token != PIPE) SyntaxError("vertical bar expected");
 NextToken();

 Pres.rels = RelList();
 Pres.nrrels = 0;
 while (Pres.rels[Pres.nrrels]) Pres.nrrels++;

 if (Token != RANGLE)
  SyntaxError("presentation has to be closed by '>'");
}

node    *ReadWord(void) {

 node    *n;

 if (Token != SEMICOLON) n = Word();
 else {
  NextToken();
  return ReadWord();
 }

 if (Token != SEMICOLON)
  SyntaxError("word has to be finished by ';'");

 return  n;
}

/*
**    ----------------------- EVALUATOR ------------------------
**    The fourth part of this file contains the evaluator.
*/

static EvalFunc EvalFunctions[TLAST];

void    SetEvalFunc(EvalType type, EvalFunc function) {
 if (type <= TNUM || type >= TLAST) {
  printf("Evaluation error: illegal type in SetEvalFunc()\n");
  exit(1);
 }

 EvalFunctions[type] = function;
}

void    *EvalNode(node *n) {
 void          *e, *l, *r;

 if (n->type == TNUM)
  return (void *) & (n->cont.n);

 switch (n->type) {
 case TGEN:                  /* TGEN is a unary node. */
  return WordGen(n->cont.g);

 case TCOMM:                 /* Adjust the class.     */
  Class--;
  l = EvalNode(n->cont.op.l);
  if (l != (void *)0) r = EvalNode(n->cont.op.r);
  Class++;

  if (l == (void *)0) return l;
  if (r == (void *)0) { Free(l); return r; }

  return WordComm((word)l, (word)r);

 case TENGEL:                /* TENGEL is a ternary node. */

  if ((e = EvalNode(n->cont.op.e)) == (void *)0) return e;

  Class -= *(int *)e;
  l = EvalNode(n->cont.op.l);
  if (l != (void *)0) r = EvalNode(n->cont.op.r);
  Class += *(int *)e;

  if (l == (void *)0) { Free(e); return l; }
  if (r == (void *)0) { Free(e); Free(l); return r; }

  return WordEngel((word)l, (word)r, (int *)e);

 default:

  if (EvalFunctions[n->type] == 0) {
   fprintf(stderr, "No evaluation function for type %d.\n", n->type);
   exit(5);
  }

  if ((l = EvalNode(n->cont.op.l)) == (void *)0) return l;
  if ((r = EvalNode(n->cont.op.r)) == (void *)0) {
   Free(l);
   return r;
  }

  return (*EvalFunctions[n->type])((word)l, r);
 }
}

static
void    TraverseNode(node *n, gen *igens) {
 if (n->type == TNUM) return;

 if (n->type == TGEN) {
  if (WordGen(n->cont.g) == (void *)0)

   igens[ n->cont.g - NumberOfAbstractGens() ] = 1;

  return;
 }

 TraverseNode(n->cont.op.l, igens);
 TraverseNode(n->cont.op.r, igens);
}

int  NrIdenticalGensNode = 0;
gen  *IdenticalGenNumberNode = 0;

int  NumberOfIdenticalGensNode(node *n) {
 gen  g,  nr;

 if (IdenticalGenNumberNode != (gen *)0)
  Free(IdenticalGenNumberNode);

 IdenticalGenNumberNode =
     (gen *)Allocate((NumberOfIdenticalGens() + 1) * sizeof(gen));

 TraverseNode(n, IdenticalGenNumberNode);

 for (nr = 0, g = 1; g <= NumberOfIdenticalGens(); g++)
  if (IdenticalGenNumberNode[ g ] == 1)
   IdenticalGenNumberNode[ g ] = ++nr;

 NrIdenticalGensNode = nr;
 return nr;
}

void    **EvalRelations(void) {

 void     **results;
 unsigned r;

 results = (void **)Allocate((Pres.nrrels + 1) * sizeof(void *));
 for (r = 0; r < Pres.nrrels; r++)
  results[r] = EvalNode(Pres.rels[r]);

 results[r] = (void *)0;
 return results;
}

/*
**    ----------------------- PRINTING ------------------------
**    And the last part contains the print functions.
*/


/*
**    PrintNum() prints an integer.
*/

static void     PrintNum(int n) {
 fprintf(OutFp, "%d", n);
}

/*
**    PrintGen() prints a generator.
*/

void    PrintGen(gen g) {
 fprintf(OutFp, "%s", GenName(g));
}

/*
**    PrintComm() prints a commutator using the following rule for
**    left normed commutators :
**                              [[a,b],c] = [a,b,c]
*/

static void     PrintComm(node *l, node *r, int bracket) {
 if (bracket) fprintf(OutFp, "[");

 /* If the left operand is a commutator, don't print its brackets. */
 if (l->type == TCOMM)
  PrintComm(l->cont.op.l, l->cont.op.r, 0);
 else
  PrintNode(l);

 fprintf(OutFp, ",");
 PrintNode(r);

 if (bracket) fprintf(OutFp, "]");
}

/*
**    PrintEngel() prints a commutator using the following rule for
**    Engel relations:
**                              [u, n v]
*/

static void     PrintEngel(node *l, node *r, node *e) {
 fprintf(OutFp, "[");
 PrintNode(l);
 fprintf(OutFp, ", ");
 PrintNode(e);
 fprintf(OutFp, " ");
 PrintNode(r);
 fprintf(OutFp, "]");
}

/*
**    PrintMult() prints a product. It is not necessary to check if
**    parentheses have to be printed since '*' has the lowest precedence
**    of all operators except '='. But '=' can only occur at the top of
**    an expression tree.
*/

static void     PrintMult(node *l, node *r) {
 PrintNode(l);
 fprintf(OutFp, "*");
 PrintNode(r);
}

/*
**    PrintPow() prints an expression raised to an integer. If the expression
**    is a product, it has to be enclosed in parentheses because of the lower
**    precedence of '*'. If the expression is again a power or a conjugation,
**    it has to be enclosed in parenthesis because '^' is not an associative
**    operator.
*/

static void     PrintPow(node *l, node *r) {
 if (l->type == TPOW || l->type == TCONJ || l->type == TMULT) {
  putc('(', OutFp);
  PrintNode(l);
  putc(')', OutFp);
 } else
  PrintNode(l);

 putc('^', OutFp);
 if (r->type != TNUM) {
  fprintf(OutFp, "Fatal error in tree.\n");
  exit(5);
 }
 fprintf(OutFp, "%d", r->cont.n);
}

/*
**    PrintConj() prints an expression conjugated by another expression.
**    If one of the expressions is a product, a power or another conjugation,
**    it has to be enclosed in parentheses for the same reasons PrintPow()
**    has to enclose the basis in parentheses.
*/

static void     PrintConj(node *l, node *r) {
 if (l->type == TPOW || l->type == TCONJ || l->type == TMULT) {
  putc('(', OutFp);
  PrintNode(l);
  putc(')', OutFp);
 } else
  PrintNode(l);

 putc('^', OutFp);

 if (r->type == TPOW || r->type == TCONJ || r->type == TMULT) {
  putc('(', OutFp);
  PrintNode(r);
  putc(')', OutFp);
 } else
  PrintNode(r);
}

/*
**    PrintRel() prints a relation. No parenthesis are necessary since
**    '=' has the lowest precedence of all binary operators.
*/

static void     PrintRel(node *l, node *r) {
 PrintNode(l);
 fprintf(OutFp, " = ");
 PrintNode(r);
}

/*
**    PrintDRelL() prints a defining relation. No parenthesis are necessary
**    since '=:' has the lowest precedence of all binary operators.
*/

static void     PrintDRelL(node *l, node *r) {
 PrintNode(l);
 fprintf(OutFp, " := ");
 PrintNode(r);
}

/*
**    PrintDRelR() prints a defining relation. No parenthesis are necessary
**    since '=:' has the lowest precedence of all binary operators.
*/

static void     PrintDRelR(node *l, node *r) {
 PrintNode(l);
 fprintf(OutFp, " =: ");
 PrintNode(r);
}

/*
**    PrintNode() just looks at the type of a node and then calls the
**    appropriate print function.
*/

void    PrintNode(node *n) {
 switch (n->type) {
 case TNUM:
 { PrintNum(n->cont.n); break; }
 case TGEN:
 { PrintGen(n->cont.g); break; }
 case TMULT:
 { PrintMult(n->cont.op.l, n->cont.op.r); break; }
 case TPOW:
 { PrintPow(n->cont.op.l, n->cont.op.r); break; }
 case TCONJ:
 { PrintConj(n->cont.op.l, n->cont.op.r); break; }
 case TCOMM:
 { PrintComm(n->cont.op.l, n->cont.op.r, 1); break; }
 case TREL:
 { PrintRel(n->cont.op.l, n->cont.op.r); break; }
 case TDRELL:
 { PrintDRelL(n->cont.op.l, n->cont.op.r); break; }
 case TDRELR:
 { PrintDRelR(n->cont.op.l, n->cont.op.r); break; }
 case TENGEL: {
  PrintEngel(n->cont.op.l, n->cont.op.r,
             n->cont.op.e);
  break;
 }
 default:
 { fprintf(OutFp, "\nunknown node type\n"); exit(5); }
 }
}

/*
**    PrintPresentation() prints the presentation stored in the global
**    variable Pres.
*/

void    PrintPresentation(FILE *fp) {
 gen     g;
 int     r;

 InitPrint(fp);

 if (Pres.nragens == 0) return;

 /* Open the presentation. */
 fprintf(OutFp, "< ");

 /* Print the generators first. */
 PrintGen(1);
 for (g = 2; g <= (gen)Pres.nragens; g++) {
  fprintf(OutFp, ", ");
  PrintGen(g);
 }

 if (Pres.nrigens > 0) {
  fprintf(OutFp, "; ");
  PrintGen(Pres.nragens + 1);
  for (g = Pres.nragens + 2; g <= (gen)(Pres.nragens + Pres.nrigens); g++) {
   fprintf(OutFp, ", ");
   PrintGen(g);
  }
 }

 /* Now the delimiter. */
 fprintf(OutFp, " |\n");

 /* Now the relations. */
 if (Pres.rels[0] != (node *)0) {
  fprintf(OutFp, " ");
  PrintNode(Pres.rels[0]);
 }
 for (r = 1; Pres.rels[r] != (node *)0; r++) {
  fprintf(OutFp, ",\n ");
  PrintNode(Pres.rels[r]);
 }

 /* And close the presentation. */
 fprintf(OutFp, " >\n");
}

void    InitPrint(FILE *fp) {
 OutFp = fp;
 OutFileName = "";
}

94%


¤ Dauer der Verarbeitung: 0.47 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge