diff --git a/util/topgen/CMakeLists.txt b/util/topgen/CMakeLists.txt new file mode 100644 index 000000000..96a1740c5 --- /dev/null +++ b/util/topgen/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required (VERSION 3.2) +project(em_topgen) +set(SRC + main.c + topgen.c + Lpars.c + LLlex.c + symtab.c + symtab.h + pattern.c + hash.c + token.h + tunable.h +) +set(INCLUDE_DIRS + . + ${CMAKE_CURRENT_BINARY_DIR} +) +add_custom_command( + OUTPUT topgen.c Lpars.c Lpars.h + COMMAND ${CMAKE_COMMAND} -E env LLGEN_LIB_DIR=${CMAKE_CURRENT_SOURCE_DIR}/../LLgen/lib ${CMAKE_CURRENT_BINARY_DIR}/../LLgen/LLgen "${CMAKE_CURRENT_SOURCE_DIR}/topgen.g" + # COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../LLgen/llgen "${CMAKE_CURRENT_SOURCE_DIR}/topgen.g" + MAIN_DEPENDENCY topgen.g + DEPENDS LLgen) +add_executable(topgen ${SRC}) +target_include_directories(topgen PRIVATE ${INCLUDE_DIRS}) +target_link_libraries(topgen) +install(TARGETS topgen DESTINATION bin) diff --git a/util/topgen/LLlex.c b/util/topgen/LLlex.c index fb156d4d0..64d9cb352 100644 --- a/util/topgen/LLlex.c +++ b/util/topgen/LLlex.c @@ -21,8 +21,11 @@ static struct token aside; /* to put currrent token aside, when a token int newline, lineno; /* To keep track of linenumbers */ extern FILE *input; /* file descriptor of machine table */ -LLlex() { - register c; +extern void error(char *s, char* s1); + + +int LLlex(void) { + register int c; if (aside.t_tokno) { /* A token was pushed aside, return it now */ dot = aside; @@ -52,7 +55,7 @@ LLlex() { if (c == EOF) { c = lineno; lineno = l; - error("Unterminated comment"); + error("Unterminated comment", ""); lineno = c; c = EOF; } @@ -116,13 +119,14 @@ LLlex() { } } -LLmessage(d) { +void LLmessage(int d) +{ static int savlineno; if (savlineno != lineno) { /* Only an error message if on another line number */ savlineno = lineno; - error("Syntax error"); + error("Syntax error",""); } if (d > 0) { /* "d" is the token to be inserted. diff --git a/util/topgen/hash.c b/util/topgen/hash.c index 03b214ecc..cafe26d69 100644 --- a/util/topgen/hash.c +++ b/util/topgen/hash.c @@ -8,83 +8,89 @@ * maintains the the lists of hashed patterns * Functions : addtohashtable() and printhashtable() */ - + #include #include #include #include "misc.h" +#include "hash.h" -struct hlist { /* linear list of pattern numbers */ - int h_patno; - struct hlist *h_next; +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 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; { +static unsigned hash(char* string) +{ register char *p; - register unsigned i,sum; + register unsigned i, sum; - if (strcmp(string,"ANY") == 0) return 128; - for (sum=i=0,p=string;*p;i += 3) - sum += (*p++)<<(i&03); + if (strcmp(string, "ANY") == 0) + return 128; + for (sum = i = 0, p = string; *p; i += 3) + sum += (*p++) << (i & 03); return sum % 128; } +void addtohashtable(char* s, int n) +{ + /* + * Add a new pattern number to the hashtable. + * s is the key, n the pattern number + */ + unsigned hval; + register struct hlist *p; -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; - - 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; + 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) - */ +static void prhlist(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); - } + 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[] = {\n",genc); - for (i = 1; i <= 128; i++) fprintf(genc,"\thash%d,\n",i); - fputs("\thashany\n};\n",genc); +void printhashtable(void) +{ + /* + * Print the linear lists, and also output an array of + * pointers to them + */ + register int i; + + 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[] = {\n", genc); + for (i = 1; i <= 128; i++) + fprintf(genc, "\thash%d,\n", i); + fputs("\thashany\n};\n", genc); } diff --git a/util/topgen/hash.h b/util/topgen/hash.h new file mode 100644 index 000000000..af54c0ab6 --- /dev/null +++ b/util/topgen/hash.h @@ -0,0 +1,23 @@ +/* + * hash.h + * + * Created on: 2018-11-24 + * Author: carl + */ + +#ifndef __HASH_H_INCLUDED__ +#define __HASH_H_INCLUDED__ + +/* + * Add a new pattern number to the hashtable. + * s is the key, n the pattern number + */ +void addtohashtable(char* s, int n); +/* + * Print the linear lists, and also output an array of + * pointers to them + */ +void printhashtable(void); + + +#endif /* __HASH_H_INCLUDED__ */ diff --git a/util/topgen/main.c b/util/topgen/main.c index 2f211f837..35e0585d7 100644 --- a/util/topgen/main.c +++ b/util/topgen/main.c @@ -11,6 +11,7 @@ #include #include +#include "Lpars.h" extern int lineno, newline; @@ -19,8 +20,10 @@ static int nerrors; char *linedir = "#line %d \"%s\"\n"; /* format of line directive */ char *inpfile; -main(argc,argv) char *argv[]; { +extern void LLparse(void); +int main(int argc,char* argv[]) +{ newline = 1; if (argc != 3) { fprintf(stderr,"Usage : %s targetoptimizerdescription outputdir\n",argv[0]); @@ -48,15 +51,16 @@ main(argc,argv) char *argv[]; { } /* VARARGS1 */ -error(s, s1) char *s, *s1; { - +void error(char *s, char* s1) +{ nerrors++; fprintf(stderr,"\"%s\", line %d: ",inpfile,lineno); fprintf(stderr,s,s1); putc('\n',stderr); } -onlyspace(s) register char *s; { +int onlyspace(register char* s) +{ while (*s) { if (*s != ' ' && *s != '\t' && *s != '\n') return 0; diff --git a/util/topgen/pattern.c b/util/topgen/pattern.c index db6ad6268..9e84f5059 100644 --- a/util/topgen/pattern.c +++ b/util/topgen/pattern.c @@ -32,7 +32,8 @@ static struct pattern *pattable, /* ptr to pattern array */ * be allocated */ -addpattern(str,l,np,nr) char *str; { +void addpattern(char* str,int l,int np,int nr) +{ /* * Just add a pattern to the list. * "str" is the constraint, "l" is the line number, @@ -62,8 +63,8 @@ addpattern(str,l,np,nr) char *str; { p->p_nrepl = nr; } -static -prconstraint(str) char *str; { +static void prconstraint(char* str) +{ /* * prints a constraint, with variable names replaced */ @@ -104,13 +105,13 @@ prconstraint(str) char *str; { } } -printpatterns() { +void printpatterns(void) { /* * Prints the pattern_descr table and generates the routine * "check_constraint" */ register struct pattern *p; - register i; + register int i; p = pattable; i = 1; @@ -127,7 +128,7 @@ printpatterns() { while (p < current) { if (p->p_constraint) { /* The pattern has a constraint */ - fprintf(genc,"\tcase %d :\n",p - pattable); + fprintf(genc,"\tcase %d :\n",(int)(p - pattable)); fprintf(genc,linedir,p->p_lineno,inpfile); /* linedirective */ fputs("\tr = (",genc); prconstraint(p->p_constraint); diff --git a/util/topgen/pattern.h b/util/topgen/pattern.h new file mode 100644 index 000000000..863fb0557 --- /dev/null +++ b/util/topgen/pattern.h @@ -0,0 +1,27 @@ +/* + * pattern.h + * + * Created on: 2018-11-25 + * Author: carl + */ + +#ifndef __PATTERN_H_INCLUDED__ +#define __PATTERN_H_INCLUDED__ + + +/* + * 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 + */ +void addpattern(char* str,int l,int np,int nr); + +/* + * Prints the pattern_descr table and generates the routine + * "check_constraint" + */ +void printpatterns(void); + +#endif /* __PATTERN_H_INCLUDED__ */ diff --git a/util/topgen/symtab.c b/util/topgen/symtab.c index b5511d0dc..da1af3dfd 100644 --- a/util/topgen/symtab.c +++ b/util/topgen/symtab.c @@ -15,6 +15,8 @@ struct symtab *idtable, *deftable; +extern void error(char *s, char* s1); + struct symtab * findident(s, mode, table) char *s; struct symtab **table; { /* @@ -24,7 +26,7 @@ findident(s, mode, table) char *s; struct symtab **table; { * table yet, otherwise an error results */ register struct symtab *p; - register n; + register int n; if (!*table) { /* No entry for this symbol */ if (mode == LOOKING) return (struct symtab *) 0; diff --git a/util/topgen/topgen.g b/util/topgen/topgen.g index 45c573e94..1d0284d63 100644 --- a/util/topgen/topgen.g +++ b/util/topgen/topgen.g @@ -1,311 +1,320 @@ -/* $Id$ */ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -/* 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 -#include -#include -#include "token.h" -#include "symtab.h" -#include "misc.h" - -char idbuf[BUFSIZ], buf[BUFSIZ]; -int countid; /* # of variables */ -int countpat; /* # of patterns */ -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 - { register int c; - fprintf(genc, linedir, lineno, inpfile); - while ((c = getc(input)) != EOF) { - putc(c,genc); - } - } -; - -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 = 0;} : - 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) { - fprintf(genc,"%c{\"\",-1,\"\"}",count == 1 ? ' ' : ','); - } - putc('}',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(int c;) - { register struct symtab *p = 0;} : - { fprintf(genc, "%c{\"", c);} - [ - 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++) { - fprintf(genc, "%c{\"\",-1,\"\"}",i?',':' '); - } - fputs("}}",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 -; +/* $Id$ */ +/* + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ +/* 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 +#include +#include +#include "token.h" +#include "symtab.h" +#include "misc.h" +#include "hash.h" +#include "pattern.h" + +char idbuf[BUFSIZ], buf[BUFSIZ]; +int countid; /* # of variables */ +int countpat; /* # of patterns */ +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 */ + + + +extern int onlyspace(char* s); +extern void error(char *s, char* s1); + + +} + +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 + { register int c; + fprintf(genc, linedir, lineno, inpfile); + while ((c = getc(input)) != EOF) { + putc(c,genc); + } + } +; + +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 = 0;} : + 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) { + fprintf(genc,"%c{\"\",-1,\"\"}",count == 1 ? ' ' : ','); + } + putc('}',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(int c;) + { register struct symtab *p = 0;} : + { fprintf(genc, "%c{\"", c);} + [ + 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 int 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++) { + fprintf(genc, "%c{\"\",-1,\"\"}",i?',':' '); + } + fputs("}}",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 +;