--- /dev/null
+/* L L l e x . c
+ *
+ * Very simple lexical analyzer.
+ * Also contains LLmessage().
+ */
+# include <ctype.h>
+# include <stdio.h>
+# include "tunable.h"
+# include "token.h"
+# include "Lpars.h"
+
+struct token dot; /* current token */
+static struct token aside; /* to put currrent token aside, when a token
+ * is inserted
+ */
+int newline, lineno; /* To keep track of linenumbers */
+extern FILE *input; /* file descriptor of machine table */
+
+LLlex() {
+ register c;
+
+ if (aside.t_tokno) { /* A token was pushed aside, return it now */
+ dot = aside;
+ aside.t_tokno = 0;
+ return dot.t_tokno;
+ }
+ if (newline) { /* delayed increment of lineno, needed to give
+ * correct line numbers in error messages
+ */
+ lineno++;
+ newline = 0;
+ }
+ c = getc(input);
+ while (c == '/') { /* Could be a comment */
+ if ((c = getc(input)) == '*') {
+ /* Yes, it is a comment */
+ int l;
+
+ l = lineno;
+ do {
+ do {
+ if (c == '\n') lineno++;
+ c = getc(input);
+ } while (c != '*' && c != EOF);
+ if (c != EOF) c = getc(input);
+ } while (c != '/' && c != EOF);
+ if (c == EOF) {
+ c = lineno;
+ lineno = l;
+ error("Unterminated comment");
+ lineno = c;
+ c = EOF;
+ }
+ else c = getc(input);
+ }
+ else {
+ ungetc(c, stdin);
+ c = '/';
+ break;
+ }
+ }
+ dot.t_tokno = c;
+ dot.t_attrib = c;
+ if (isupper(c) || islower(c) || c == '_') {
+ dot.t_tokno = LETTER;
+ return LETTER;
+ }
+ if (isdigit(c)) {
+ dot.t_tokno = DIGIT;
+ return DIGIT;
+ }
+ switch(c) {
+ case line_term :
+ dot.t_tokno = LINE_TERMINATOR;
+ return LINE_TERMINATOR;
+ case operand_sep :
+ dot.t_tokno = OPERAND_SEPARATOR;
+ return OPERAND_SEPARATOR;
+ case instruction_sep :
+ dot.t_tokno = INSTRUCTION_SEPARATOR;
+ return INSTRUCTION_SEPARATOR;
+ case '-' :
+ c = getc(input);
+ if (c == '>') {
+ dot.t_tokno = PATTERN_SEPARATOR;
+ return PATTERN_SEPARATOR;
+ }
+ ungetc(c,stdin);
+ dot.t_tokno = OTHER;
+ return OTHER;
+ case open_bracket :
+ dot.t_tokno = OPEN_BRACKET;
+ return OPEN_BRACKET;
+ case close_bracket :
+ dot.t_tokno = CLOSE_BRACKET;
+ return CLOSE_BRACKET;
+ case '\n' :
+ newline = 1;
+ /* Fall through */
+ case ' ' :
+ case '\t' :
+ dot.t_tokno = SPACE;
+ return SPACE;
+ case '%' :
+ case EOF :
+ return c;
+ default :
+ /* Let the C-compiler find out what is illegal! */
+ dot.t_tokno = OTHER;
+ return OTHER;
+ }
+}
+
+LLmessage(d) {
+ static int savlineno;
+
+ if (savlineno != lineno) {
+ /* Only an error message if on another line number */
+ savlineno = lineno;
+ error("Syntax error");
+ }
+ if (d > 0) {
+ /* "d" is the token to be inserted.
+ * This is the place to put the current token aside and
+ * give the inserted token an attribute ... but who cares
+ */
+ aside = dot;
+ }
+}
--- /dev/null
+EM = ../..
+CFLAGS = -O
+SOURCE = token.h symtab.h misc.h tunable.h main.c topgen.g LLlex.c symtab.c pattern.c hash.c
+CFILES = main.c topgen.c Lpars.c LLlex.c symtab.c pattern.c hash.c
+OFILES = main.o topgen.o Lpars.o LLlex.o symtab.o pattern.o hash.o
+
+all: parser
+ @make topgen
+
+cmp: all
+ cmp topgen $(EM)/lib/topgen
+
+install: all
+ cp topgen $(EM)/lib/topgen
+
+clean:
+ rm -f topgen *.o Lpars.c Lpars.h topgen.c parser
+
+parser: topgen.g
+ $(EM)/bin/LLgen topgen.g
+ touch parser
+
+topgen.o: token.h Lpars.h symtab.h misc.h
+Lpars.o: Lpars.h
+LLlex.o: token.h Lpars.h tunable.h
+symtab.o: symtab.h
+hash.o: misc.h
+pattern.o: misc.h symtab.h
+
+topgen: $(OFILES)
+ cc $(OFILES) -o topgen
+
+lint: parser
+ lint $(CFILES)
+
+pr:
+ @pr $(SOURCE) Makefile
+
+opr:
+ make pr ^ opr
--- /dev/null
+/* h a s h . c
+ *
+ * maintains the the lists of hashed patterns
+ * Functions : addtohashtable() and printhashtable()
+ */
+# include <stdio.h>
+# include "misc.h"
+
+struct hlist { /* linear list of pattern numbers */
+ int h_patno;
+ struct hlist *h_next;
+};
+
+static struct hlist *hashtable[129]; /* an array of ptr's to these lists,
+ * the index in the array is the
+ * result of hashing
+ */
+
+static unsigned
+hash(string) char *string; {
+ register char *p;
+ register unsigned i,sum;
+
+ if (strcmp(string,"ANY") == 0) return 128;
+ for (sum=i=0,p=string;*p;i += 3)
+ sum += (*p++)<<(i&07);
+ return sum % 127;
+}
+
+
+addtohashtable(s,n) char *s; {
+ /*
+ * Add a new pattern number to the hashtable.
+ * s is the key, n the pattern number
+ */
+ unsigned hval;
+ register struct hlist *p;
+ char *malloc();
+
+ hval = hash(s);
+ p = (struct hlist *) malloc(sizeof *p);
+ p->h_patno = n;
+ /*
+ * Now insert in front of the list
+ * This way, the list will be sorted from high to low, which is the
+ * wrong way around, but easy
+ */
+ p->h_next = hashtable[hval];
+ hashtable[hval] = p;
+}
+
+static
+prhlist(p) struct hlist *p; {
+ /*
+ * Print a list in reversed order (see comment above)
+ */
+
+ if (p) {
+ prhlist(p->h_next);
+ fprintf(genc,"%d, ",p->h_patno - 1);
+ }
+}
+
+printhashtable() {
+ /*
+ * Print the linear lists, and also output an array of
+ * pointers to them
+ */
+ register i;
+ register struct hlist *p;
+
+ for (i = 1; i <= 128; i++) {
+ fprintf(genc,"int hash%d[] = { ",i);
+ prhlist(hashtable[i-1]);
+ fputs("-1};\n",genc);
+ }
+ fputs("int hashany[] = { ", genc);
+ prhlist(hashtable[128]);
+ fputs("-1 };\n",genc);
+ fputs("int *hashtab[] = {",genc);
+ for (i = 1; i <= 128; i++) fprintf(genc,"hash%d,",i);
+ fputs("hashany};\n",genc);
+}
--- /dev/null
+/* m a i n . c
+ *
+ * Contains the main program, the error reporting routine, and a routine
+ * to check wether a constraint consists only of space
+ */
+# include <stdio.h>
+
+extern int lineno, newline;
+
+FILE *genc, *genh, *input;
+static int nerrors;
+char *linedir = "#line %d \"%s\"\n"; /* format of line directive */
+char *inpfile;
+
+main(argc,argv) char *argv[]; {
+
+ newline = 1;
+ if (argc != 2) {
+ fprintf(stderr,"Usage : %s targetoptimizerdescription\n",argv[0]);
+ return 1;
+ }
+ if ((input = fopen(argv[1],"r")) == NULL) {
+ fprintf(stderr,"Fatal error : couldn't open %s\n",argv[1]);
+ return 1;
+ }
+ if ((genc = fopen("gen.c","w")) == NULL) {
+ fputs("Fatal error : couldn't open gen.c\n",stderr);
+ return 1;
+ }
+ if ((genh = fopen("gen.h","w")) == NULL) {
+ fputs("Fatal error : couldn't open gen.h\n",stderr);
+ return 1;
+ }
+ inpfile = argv[1]; /* needed for line directives and errors */
+ LLparse();
+ if (nerrors) return 1;
+ return 0;
+}
+
+/* VARARGS1 */
+error(s, s1) char *s, *s1; {
+
+ nerrors++;
+ fprintf(stderr,"\"%s\", line %d: ",inpfile,lineno);
+ fprintf(stderr,s,s1);
+ putc('\n',stderr);
+}
+
+onlyspace(s) register char *s; {
+
+ while (*s) {
+ if (*s != ' ' && *s != '\t' && *s != '\n') return 0;
+ s++;
+ }
+ return 1;
+}
--- /dev/null
+/* m i s c . h
+ *
+ * Some external declarations
+ */
+extern int countid; /* # of variables */
+extern int countpat; /* # of patterns */
+extern int lineno; /* line number */
+extern FILE *genc, *genh; /* Output files */
+extern char *inpfile; /* input file name */
+extern char *linedir; /* line directive format */
--- /dev/null
+/* p a t t e r n . c
+ *
+ * Deals with the pattern stuff.
+ * it maintains a table of information about the patterns
+ * Functions : addpattern() and printpatterns()
+ */
+# include <stdio.h>
+# include <ctype.h>
+# include "misc.h"
+# include "symtab.h"
+
+struct pattern {
+ char *p_constraint; /* constraint of this pattern */
+ int p_lineno, /* line number of constraint */
+ p_npat, /* # of instructions in pattern */
+ p_nrepl; /* # of instructions in replacement */
+};
+
+static struct pattern *pattable, /* ptr to pattern array */
+ *current, /* ptr to first unoccupied el of
+ * pattern array
+ */
+ *maxpat; /* if beyond this, new space must
+ * be allocated
+ */
+
+addpattern(str,l,np,nr) char *str; {
+ /*
+ * Just add a pattern to the list.
+ * "str" is the constraint, "l" is the line number,
+ * "np" is the number of instructions in the pattern,
+ * "nr" is the number of instructions in the replacement
+ * Space is allocated in chunks of 50
+ */
+ char *malloc(), *realloc();
+ register struct pattern *p;
+
+ if (!pattable) { /* No space allocated yet */
+ pattable = (struct pattern *) malloc(50 * sizeof *pattable);
+ current = pattable;
+ maxpat = pattable + 50;
+ }
+ if (current >= maxpat) { /* Allocate some new space */
+ p = pattable;
+ pattable = (struct pattern *) realloc(
+ (char *) pattable,
+ (unsigned) (sizeof *pattable * (50 + (maxpat - pattable))));
+ current = pattable + (current - p);
+ maxpat = pattable + (maxpat - p) + 50;
+ }
+ p = current++;
+ p->p_constraint = str;
+ p->p_lineno = l;
+ p->p_npat = np;
+ p->p_nrepl = nr;
+}
+
+static
+prconstraint(str) char *str; {
+ /*
+ * prints a constraint, with variable names replaced
+ */
+ char c;
+ register char *p, *q;
+ struct symtab *name;
+
+ p = str;
+ while (*p) {
+ if (isupper(*p) || islower(*p) || *p == '_') {
+ /*
+ * Start of identifier
+ */
+ q = p + 1;
+ while (*q && (
+ isupper(*q) || islower(*q) || isdigit(*q) || *q == '_')) {
+ q++;
+ }
+ c = *q;
+ *q = '\0';
+ /* Temporarily let it end with null byte */
+ name = findident(p,LOOKING,&idtable);
+ if (name) { /* yeah, it was a variable */
+ fprintf(genc,"var[%d].value", name->s_num);
+ }
+ else fputs(p,genc);
+ /* Now replace null byte with whatever used to be there */
+ *q = c;
+ p = q;
+ }
+ else {
+ putc(*p,genc);
+ p++;
+ }
+ }
+}
+
+printpatterns() {
+ /*
+ * Prints the pattern_descr table and generates the routine
+ * "check_constraint"
+ */
+ register struct pattern *p;
+ register i;
+
+ p = pattable;
+ i = 1;
+ fputs("struct pattern_descr patterns[] = {\n", genc);
+ while (p != current) {
+ fprintf(genc," {%d,pat%d,%d,rep%d,},\n",
+ p->p_npat, i, p->p_nrepl, i);
+ p++;
+ i++;
+ }
+ fputs("};\n", genc);
+ fputs("int\ncheck_constraint(patno){\n\tint r;\n\tswitch(patno){\n",genc);
+ p = pattable;
+ while (p < current) {
+ if (p->p_constraint) {
+ /* The pattern has a constraint */
+ fprintf(genc,"\tcase %d :\n",p - pattable);
+ fprintf(genc,linedir,p->p_lineno,inpfile); /* linedirective */
+ fputs("\tr = (",genc);
+ prconstraint(p->p_constraint);
+ fputs("); break;\n",genc);
+ }
+ p++;
+ }
+ fputs("\tdefault :\n\t\tr = 1;\n\t}\n\treturn r;\n}\n\n",genc);
+}
--- /dev/null
+/* s y m t a b . c
+ *
+ * Contains the routine findident, which builds the symbol table and
+ * searches identifiers
+ */
+# include "symtab.h"
+
+struct symtab *idtable, *deftable;
+
+struct symtab *
+findident(s, mode, table) char *s; struct symtab **table; {
+ /*
+ * Look for identifier s in the symboltable referred to by *table.
+ * If mode = LOOKING, no new entry's will be made.
+ * If mode = ENTERING, a new entry will be made if s is not in the
+ * table yet, otherwise an error results
+ */
+ char *malloc();
+ char *strcpy();
+ register struct symtab *p;
+ register n;
+
+ if (!*table) { /* No entry for this symbol */
+ if (mode == LOOKING) return (struct symtab *) 0;
+ /*
+ * Make new entry
+ */
+ p = (struct symtab *) malloc(sizeof *p);
+ p->s_left = p->s_right = (struct symtab *) 0;
+ p->s_name = malloc( (unsigned) (strlen(s) + 1));
+ strcpy(p->s_name,s);
+ *table = p;
+ return p;
+ }
+ else {
+ p = *table;
+ if ((n = strcmp(p->s_name,s)) == 0) { /* This is it! */
+ if (mode == ENTERING) {
+ error("Identifier %s redefined",s);
+ }
+ return p;
+ }
+ /* Binary tree ..... */
+ if (n < 0) return findident(s,mode,&(p->s_left));
+ return findident(s,mode,&(p->s_right));
+ }
+ /* NOTREACHED */
+}
--- /dev/null
+/* s y m t a b . h
+ *
+ * Contains a structure declaration for a symbol table that is a
+ * binary tree
+ */
+struct symtab {
+ char *s_name; /* The name of the symbol */
+ int s_num; /* it's number */
+ struct symtab *s_left, *s_right;
+};
+
+extern struct symtab *idtable, /* table for variables */
+ *deftable; /* table for tunable defines */
+struct symtab *findident();
+
+/* Options to "findident" */
+#define LOOKING 1
+#define ENTERING 0
--- /dev/null
+/* t o k e n . h
+ *
+ * Contains the structure declaration for a token
+ */
+struct token {
+ int t_tokno; /* token number */
+ char t_attrib; /* it's attribute (always a character) */
+};
+
+extern struct token dot; /* current token */
--- /dev/null
+/* t o p g e n . g
+ *
+ * Grammar of optimizer description, and some code generation
+ */
+
+%token LETTER, DIGIT, OTHER, SPACE;
+%token LINE_TERMINATOR, OPERAND_SEPARATOR, INSTRUCTION_SEPARATOR,
+ PATTERN_SEPARATOR, OPEN_BRACKET, CLOSE_BRACKET;
+%lexical LLlex;
+%start LLparse, optim_description;
+
+{
+# include <stdio.h>
+# include "token.h"
+# include "symtab.h"
+# include "misc.h"
+
+char idbuf[BUFSIZ], buf[BUFSIZ];
+int countid; /* # of variables */
+int countpat; /* # of patterns */
+char * malloc();
+char * strcpy();
+static int patlen; /* Maximum number of instructions in pattern */
+static int maxoperand; /* Maximum number of operands of instruction */
+extern FILE *input; /* file descriptor of inputfile */
+}
+
+optim_description
+ { struct symtab *p; } :
+ SPACE* parameter_line*
+ { p = findident("MAXOP",LOOKING,&deftable);
+ if (p == 0) maxoperand = 2; /* default */
+ else maxoperand = p->s_num;
+ }
+ separator SPACE* mode_definitions
+ separator SPACE* patterns
+ separator user_routines
+;
+
+parameter_line
+ { struct symtab *p;} :
+ identifier
+ { p = findident(idbuf,ENTERING,&deftable);}
+ SPACE
+ value
+ { p->s_num = atoi(buf);}
+ /* This action in fact only needed for MAXOP */
+ LINE_TERMINATOR
+ SPACE*
+ { fprintf(genh,"#define %s %s\n",p->s_name,buf);}
+;
+
+value
+ { char *p1 = buf;} :
+ [
+ [ OPEN_BRACKET
+ | CLOSE_BRACKET
+ | OPERAND_SEPARATOR
+ | PATTERN_SEPARATOR
+ | INSTRUCTION_SEPARATOR
+ | SPACE
+ | LETTER
+ | DIGIT
+ | OTHER
+ | '%'
+ ]
+ { *p1++ = dot.t_attrib;}
+ ]*
+ { *p1 = '\0';}
+;
+
+mode_definitions
+ { int lin; } :
+ { fputs("tok_chk(varno) {\n\tint r;\n", genc);
+ fputs("\tchar *VAL;\n\n",genc);
+ fputs("\tVAL = var[varno].value;\n",genc);
+ fputs("\tswitch(varno) {\n",genc);
+ }
+ [
+ token_list
+ constraint(&lin)
+ { fprintf(genc,linedir,lin,inpfile);
+ fprintf(genc,"\t\tr = (%s); break;\n",buf);
+ }
+ LINE_TERMINATOR
+ SPACE*
+ ]*
+ { fputs("\tdefault :\n\t\tassert(0);\n",genc);
+ fputs("\t}\n\treturn r;\n}\n\n",genc);
+ }
+;
+
+token_list :
+ new_identifier
+ SPACE*
+ [
+ OPERAND_SEPARATOR
+ SPACE*
+ new_identifier
+ SPACE*
+ ]*
+;
+
+new_identifier
+ { struct symtab *p;} :
+ identifier
+ { p = findident(idbuf,ENTERING,&idtable);
+ p->s_num = ++countid;
+ fprintf(genc,"\tcase %d:\n", countid);
+ }
+;
+
+constraint (int *lin;)
+ { char *p = buf; } :
+ OPEN_BRACKET
+ { *lin = lineno;}
+ [
+ [ LINE_TERMINATOR
+ | OPERAND_SEPARATOR
+ | PATTERN_SEPARATOR
+ | INSTRUCTION_SEPARATOR
+ | LETTER
+ | DIGIT
+ | SPACE
+ | OTHER
+ | '%'
+ ]
+ { *p++ = dot.t_attrib;}
+ ]*
+ { *p = '\0';
+ if (onlyspace(buf)) strcpy(buf,"TRUE");
+ }
+ CLOSE_BRACKET
+ SPACE*
+;
+
+patterns
+ { int lin;
+ char *constr;
+ int np, nr;
+ } :
+[
+ { countpat++;
+ constr = (char *) 0;
+ fprintf(genc,"struct instr_descr pat%d[] = {\n",
+ countpat);
+ }
+ instruction_list(&np)
+ { if (np > patlen) patlen = np;
+ fputs("\n};\n\n",genc);
+ }
+ [
+ constraint(&lin)
+ { /* Save the constraint, we need it later on */
+ constr = malloc((unsigned)(strlen(buf)+1));
+ strcpy(constr,buf);
+ }
+ ]?
+ PATTERN_SEPARATOR
+ { fprintf(genc,"struct instr_descr rep%d[] = {\n",
+ countpat);
+ }
+ replacement(&nr)
+ { fputs("\n};\n\n",genc);}
+ LINE_TERMINATOR
+ SPACE*
+ { addpattern(constr,lin,np,nr);}
+]*
+ { printhashtable();
+ printpatterns();
+ fprintf(genh,"#define NRVARS %d\n",countid);
+ fprintf(genh,"#define NRPATTERNS %d\n",countpat);
+ fprintf(genh,"#define MIN_WINDOW_SIZE %d\n",
+ patlen+3);
+ fclose(genh);
+ }
+;
+
+instruction_list(int *n;) :
+ instruction(1)
+ { *n = 1;}
+ [
+ INSTRUCTION_SEPARATOR
+ { fputs(",\n",genc);}
+ SPACE*
+ instruction(0)
+ { *n += 1;}
+ ]*
+;
+
+instruction(int opt;)
+ { int count;} :
+ opcode(opt)
+ { if (strcmp(buf,"ANY") != 0) {
+ fprintf(genc,"\t{\"%s\"",buf);
+ }
+ else fputs("\t{(char *) 0",genc);
+ count = 0;
+ }
+ [
+ operand
+ { count = 1;}
+ [
+ OPERAND_SEPARATOR
+ { count++;}
+ SPACE*
+ operand
+ ]*
+ { if (count > maxoperand) {
+ error("Too many operands");
+ }
+ }
+ ]?
+ { while (count++ < maxoperand) {
+ fputs(",{\"\",-1,\"\"}",genc);
+ }
+ putc('}',genc);
+ }
+;
+
+opcode(int opt;)
+ { char *p = buf;} :
+ [
+ [ LETTER
+ | DIGIT
+ | OTHER
+ ]
+ { *p++ = dot.t_attrib;}
+ ]+
+ SPACE+
+ { *p = '\0';
+ if (opt) addtohashtable(buf,countpat);
+ }
+;
+
+operand
+ { register struct symtab *p = 0;} :
+ { fputs(",{\"",genc);}
+ [
+ identifier
+ { if (!p) {
+ p = findident(idbuf,LOOKING,&idtable);
+ if (p) fprintf(genc,"\",%d,\"",p->s_num);
+ else fputs(idbuf,genc);
+ }
+ else fputs(idbuf,genc);
+ }
+ | DIGIT
+ { putc(dot.t_attrib,genc);}
+ | OTHER
+ { putc(dot.t_attrib,genc);}
+ ]+
+ { if (p) fputs("\"}",genc);
+ else fputs("\",0,\"\"}",genc);
+ }
+ SPACE*
+;
+
+replacement (int *n;)
+ {register i;} :
+ SPACE*
+ { *n = 0;}
+ [
+ instruction(0)
+ { *n = 1;}
+ [
+ INSTRUCTION_SEPARATOR
+ { fputs(",\n", genc);}
+ SPACE*
+ instruction(0)
+ { *n += 1;}
+ ]*
+ | /* empty replacement, but there must be a
+ * structure initializer anyway
+ */
+ { fputs("\t{\"\"",genc);
+ for (i = 0; i < maxoperand; i++) {
+ fputs(",{\"\",-1,\"\"}",genc);
+ }
+ putc('}',genc);
+ }
+ ]
+;
+
+user_routines
+ {register c;} :
+ { fprintf(genc, linedir, lineno, inpfile);
+ while ((c = getc(input)) != EOF) {
+ putc(c,genc);
+ }
+ }
+;
+
+identifier
+ { char *p = idbuf; } :
+ LETTER
+ { *p++ = dot.t_attrib;}
+ [ %while (1)
+ LETTER { *p++ = dot.t_attrib;}
+ | DIGIT { *p++ = dot.t_attrib;}
+ ]*
+ { *p = '\0';}
+;
+
+separator :
+ '%' '%' SPACE* LINE_TERMINATOR
+;
--- /dev/null
+/* t u n a b l e . h
+ *
+ * Contains some tunable constants.
+ * They should all differ, not be a letter or digit or '_', not be a '%',
+ * and not be space (' ','\t','\n' and the like).
+ */
+# define line_term ';'
+# define operand_sep ','
+# define instruction_sep ':'
+# define open_bracket '{'
+# define close_bracket '}'