Better ANSI C compatibility and portability:

+ Addition of function prototypes and include files.
+ Change function definitions to ANSI C style.
+ Initial support for CMake
This commit is contained in:
carl 2019-02-19 00:44:39 +08:00
parent cc27fd471d
commit d825e962ed
9 changed files with 491 additions and 387 deletions

View file

@ -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)

View file

@ -21,8 +21,11 @@ static struct token aside; /* to put currrent token aside, when a token
int newline, lineno; /* To keep track of linenumbers */ int newline, lineno; /* To keep track of linenumbers */
extern FILE *input; /* file descriptor of machine table */ extern FILE *input; /* file descriptor of machine table */
LLlex() { extern void error(char *s, char* s1);
register c;
int LLlex(void) {
register int c;
if (aside.t_tokno) { /* A token was pushed aside, return it now */ if (aside.t_tokno) { /* A token was pushed aside, return it now */
dot = aside; dot = aside;
@ -52,7 +55,7 @@ LLlex() {
if (c == EOF) { if (c == EOF) {
c = lineno; c = lineno;
lineno = l; lineno = l;
error("Unterminated comment"); error("Unterminated comment", "");
lineno = c; lineno = c;
c = EOF; c = EOF;
} }
@ -116,13 +119,14 @@ LLlex() {
} }
} }
LLmessage(d) { void LLmessage(int d)
{
static int savlineno; static int savlineno;
if (savlineno != lineno) { if (savlineno != lineno) {
/* Only an error message if on another line number */ /* Only an error message if on another line number */
savlineno = lineno; savlineno = lineno;
error("Syntax error"); error("Syntax error","");
} }
if (d > 0) { if (d > 0) {
/* "d" is the token to be inserted. /* "d" is the token to be inserted.

View file

@ -8,83 +8,89 @@
* maintains the the lists of hashed patterns * maintains the the lists of hashed patterns
* Functions : addtohashtable() and printhashtable() * Functions : addtohashtable() and printhashtable()
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "misc.h" #include "misc.h"
#include "hash.h"
struct hlist { /* linear list of pattern numbers */ struct hlist
int h_patno; { /* linear list of pattern numbers */
struct hlist *h_next; int h_patno;
struct hlist *h_next;
}; };
static struct hlist *hashtable[129]; /* an array of ptr's to these lists, static struct hlist *hashtable[129]; /* an array of ptr's to these lists,
* the index in the array is the * the index in the array is the
* result of hashing * result of hashing
*/ */
static unsigned static unsigned hash(char* string)
hash(string) char *string; { {
register char *p; register char *p;
register unsigned i,sum; register unsigned i, sum;
if (strcmp(string,"ANY") == 0) return 128; if (strcmp(string, "ANY") == 0)
for (sum=i=0,p=string;*p;i += 3) return 128;
sum += (*p++)<<(i&03); for (sum = i = 0, p = string; *p; i += 3)
sum += (*p++) << (i & 03);
return sum % 128; 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; { hval = hash(s);
/* p = (struct hlist *) malloc(sizeof *p);
* Add a new pattern number to the hashtable. p->h_patno = n;
* s is the key, n the pattern number /*
*/ * Now insert in front of the list
unsigned hval; * This way, the list will be sorted from high to low, which is the
register struct hlist *p; * wrong way around, but easy
*/
hval = hash(s); p->h_next = hashtable[hval];
p = (struct hlist *) malloc(sizeof *p); hashtable[hval] = 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 static void prhlist(struct hlist *p)
prhlist(p) struct hlist *p; { {
/* /*
* Print a list in reversed order (see comment above) * Print a list in reversed order (see comment above)
*/ */
if (p) { if (p)
prhlist(p->h_next); {
fprintf(genc,"%d, ",p->h_patno - 1); 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++) { void printhashtable(void)
fprintf(genc,"int hash%d[] = { ",i); {
prhlist(hashtable[i-1]); /*
fputs("-1};\n",genc); * Print the linear lists, and also output an array of
} * pointers to them
fputs("int hashany[] = { ", genc); */
prhlist(hashtable[128]); register int i;
fputs("-1 };\n",genc);
fputs("int *hashtab[] = {\n",genc); for (i = 1; i <= 128; i++)
for (i = 1; i <= 128; i++) fprintf(genc,"\thash%d,\n",i); {
fputs("\thashany\n};\n",genc); 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);
} }

23
util/topgen/hash.h Normal file
View file

@ -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__ */

View file

@ -11,6 +11,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "Lpars.h"
extern int lineno, newline; extern int lineno, newline;
@ -19,8 +20,10 @@ static int nerrors;
char *linedir = "#line %d \"%s\"\n"; /* format of line directive */ char *linedir = "#line %d \"%s\"\n"; /* format of line directive */
char *inpfile; char *inpfile;
main(argc,argv) char *argv[]; { extern void LLparse(void);
int main(int argc,char* argv[])
{
newline = 1; newline = 1;
if (argc != 3) { if (argc != 3) {
fprintf(stderr,"Usage : %s targetoptimizerdescription outputdir\n",argv[0]); fprintf(stderr,"Usage : %s targetoptimizerdescription outputdir\n",argv[0]);
@ -48,15 +51,16 @@ main(argc,argv) char *argv[]; {
} }
/* VARARGS1 */ /* VARARGS1 */
error(s, s1) char *s, *s1; { void error(char *s, char* s1)
{
nerrors++; nerrors++;
fprintf(stderr,"\"%s\", line %d: ",inpfile,lineno); fprintf(stderr,"\"%s\", line %d: ",inpfile,lineno);
fprintf(stderr,s,s1); fprintf(stderr,s,s1);
putc('\n',stderr); putc('\n',stderr);
} }
onlyspace(s) register char *s; { int onlyspace(register char* s)
{
while (*s) { while (*s) {
if (*s != ' ' && *s != '\t' && *s != '\n') return 0; if (*s != ' ' && *s != '\t' && *s != '\n') return 0;

View file

@ -32,7 +32,8 @@ static struct pattern *pattable, /* ptr to pattern array */
* be allocated * 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. * Just add a pattern to the list.
* "str" is the constraint, "l" is the line number, * "str" is the constraint, "l" is the line number,
@ -62,8 +63,8 @@ addpattern(str,l,np,nr) char *str; {
p->p_nrepl = nr; p->p_nrepl = nr;
} }
static static void prconstraint(char* str)
prconstraint(str) char *str; { {
/* /*
* prints a constraint, with variable names replaced * 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 * Prints the pattern_descr table and generates the routine
* "check_constraint" * "check_constraint"
*/ */
register struct pattern *p; register struct pattern *p;
register i; register int i;
p = pattable; p = pattable;
i = 1; i = 1;
@ -127,7 +128,7 @@ printpatterns() {
while (p < current) { while (p < current) {
if (p->p_constraint) { if (p->p_constraint) {
/* The pattern has a 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 */ fprintf(genc,linedir,p->p_lineno,inpfile); /* linedirective */
fputs("\tr = (",genc); fputs("\tr = (",genc);
prconstraint(p->p_constraint); prconstraint(p->p_constraint);

27
util/topgen/pattern.h Normal file
View file

@ -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__ */

View file

@ -15,6 +15,8 @@
struct symtab *idtable, *deftable; struct symtab *idtable, *deftable;
extern void error(char *s, char* s1);
struct symtab * struct symtab *
findident(s, mode, table) char *s; struct symtab **table; { 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 * table yet, otherwise an error results
*/ */
register struct symtab *p; register struct symtab *p;
register n; register int n;
if (!*table) { /* No entry for this symbol */ if (!*table) { /* No entry for this symbol */
if (mode == LOOKING) return (struct symtab *) 0; if (mode == LOOKING) return (struct symtab *) 0;

View file

@ -1,311 +1,320 @@
/* $Id$ */ /* $Id$ */
/* /*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright". * See the copyright notice in the ACK home directory, in the file "Copyright".
*/ */
/* t o p g e n . g /* t o p g e n . g
* *
* Grammar of optimizer description, and some code generation * Grammar of optimizer description, and some code generation
*/ */
%token LETTER, DIGIT, OTHER, SPACE; %token LETTER, DIGIT, OTHER, SPACE;
%token LINE_TERMINATOR, OPERAND_SEPARATOR, INSTRUCTION_SEPARATOR, %token LINE_TERMINATOR, OPERAND_SEPARATOR, INSTRUCTION_SEPARATOR,
PATTERN_SEPARATOR, OPEN_BRACKET, CLOSE_BRACKET; PATTERN_SEPARATOR, OPEN_BRACKET, CLOSE_BRACKET;
%lexical LLlex; %lexical LLlex;
%start LLparse, optim_description; %start LLparse, optim_description;
{ {
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "token.h" #include "token.h"
#include "symtab.h" #include "symtab.h"
#include "misc.h" #include "misc.h"
#include "hash.h"
char idbuf[BUFSIZ], buf[BUFSIZ]; #include "pattern.h"
int countid; /* # of variables */
int countpat; /* # of patterns */ char idbuf[BUFSIZ], buf[BUFSIZ];
static int patlen; /* Maximum number of instructions in pattern */ int countid; /* # of variables */
static int maxoperand; /* Maximum number of operands of instruction */ int countpat; /* # of patterns */
extern FILE *input; /* file descriptor of inputfile */ 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); extern int onlyspace(char* s);
if (p == 0) maxoperand = 2; /* default */ extern void error(char *s, char* s1);
else maxoperand = p->s_num;
}
separator SPACE* mode_definitions }
separator SPACE* patterns
separator optim_description
{ register int c; { struct symtab *p; } :
fprintf(genc, linedir, lineno, inpfile); SPACE* parameter_line*
while ((c = getc(input)) != EOF) { { p = findident("MAXOP",LOOKING,&deftable);
putc(c,genc); if (p == 0) maxoperand = 2; /* default */
} else maxoperand = p->s_num;
} }
; separator SPACE* mode_definitions
separator SPACE* patterns
parameter_line separator
{ struct symtab *p;} : { register int c;
identifier fprintf(genc, linedir, lineno, inpfile);
{ p = findident(idbuf,ENTERING,&deftable);} while ((c = getc(input)) != EOF) {
SPACE putc(c,genc);
value }
{ p->s_num = atoi(buf);} }
/* This action in fact only needed for MAXOP */ ;
LINE_TERMINATOR
SPACE* parameter_line
{ fprintf(genh,"#define %s %s\n",p->s_name,buf);} { struct symtab *p;} :
; identifier
{ p = findident(idbuf,ENTERING,&deftable);}
value SPACE
{ char *p1 = buf;} : value
[ { p->s_num = atoi(buf);}
[ OPEN_BRACKET /* This action in fact only needed for MAXOP */
| CLOSE_BRACKET LINE_TERMINATOR
| OPERAND_SEPARATOR SPACE*
| PATTERN_SEPARATOR { fprintf(genh,"#define %s %s\n",p->s_name,buf);}
| INSTRUCTION_SEPARATOR ;
| SPACE
| LETTER value
| DIGIT { char *p1 = buf;} :
| OTHER [
| '%' [ OPEN_BRACKET
] | CLOSE_BRACKET
{ *p1++ = dot.t_attrib;} | OPERAND_SEPARATOR
]* | PATTERN_SEPARATOR
{ *p1 = '\0';} | INSTRUCTION_SEPARATOR
; | SPACE
| LETTER
mode_definitions | DIGIT
{ int lin; } : | OTHER
{ fputs("tok_chk(varno) {\n\tint r;\n", genc); | '%'
fputs("\tchar *VAL;\n\n",genc); ]
fputs("\tVAL = var[varno].value;\n",genc); { *p1++ = dot.t_attrib;}
fputs("\tswitch(varno) {\n",genc); ]*
} { *p1 = '\0';}
[ ;
token_list
constraint(&lin) mode_definitions
{ fprintf(genc,linedir,lin,inpfile); { int lin; } :
fprintf(genc,"\t\tr = (%s); break;\n",buf); { fputs("tok_chk(varno) {\n\tint r;\n", genc);
} fputs("\tchar *VAL;\n\n",genc);
LINE_TERMINATOR fputs("\tVAL = var[varno].value;\n",genc);
SPACE* fputs("\tswitch(varno) {\n",genc);
]* }
{ fputs("\tdefault :\n\t\tassert(0);\n",genc); [
fputs("\t}\n\treturn r;\n}\n\n",genc); token_list
} constraint(&lin)
; { fprintf(genc,linedir,lin,inpfile);
fprintf(genc,"\t\tr = (%s); break;\n",buf);
token_list : }
new_identifier LINE_TERMINATOR
SPACE* SPACE*
[ ]*
OPERAND_SEPARATOR { fputs("\tdefault :\n\t\tassert(0);\n",genc);
SPACE* fputs("\t}\n\treturn r;\n}\n\n",genc);
new_identifier }
SPACE* ;
]*
; token_list :
new_identifier
new_identifier SPACE*
{ struct symtab *p;} : [
identifier OPERAND_SEPARATOR
{ p = findident(idbuf,ENTERING,&idtable); SPACE*
p->s_num = ++countid; new_identifier
fprintf(genc,"\tcase %d:\n", countid); SPACE*
} ]*
; ;
constraint (int *lin;) new_identifier
{ char *p = buf; } : { struct symtab *p;} :
OPEN_BRACKET identifier
{ *lin = lineno;} { p = findident(idbuf,ENTERING,&idtable);
[ p->s_num = ++countid;
[ LINE_TERMINATOR fprintf(genc,"\tcase %d:\n", countid);
| OPERAND_SEPARATOR }
| PATTERN_SEPARATOR ;
| INSTRUCTION_SEPARATOR
| LETTER constraint (int *lin;)
| DIGIT { char *p = buf; } :
| SPACE OPEN_BRACKET
| OTHER { *lin = lineno;}
| '%' [
] [ LINE_TERMINATOR
{ *p++ = dot.t_attrib;} | OPERAND_SEPARATOR
]* | PATTERN_SEPARATOR
{ *p = '\0'; | INSTRUCTION_SEPARATOR
if (onlyspace(buf)) strcpy(buf,"TRUE"); | LETTER
} | DIGIT
CLOSE_BRACKET | SPACE
SPACE* | OTHER
; | '%'
]
patterns { *p++ = dot.t_attrib;}
{ int lin; ]*
char *constr; { *p = '\0';
int np, nr; if (onlyspace(buf)) strcpy(buf,"TRUE");
} : }
[ CLOSE_BRACKET
{ countpat++; SPACE*
constr = (char *) 0; ;
fprintf(genc,"struct instr_descr pat%d[] = {\n",
countpat); patterns
} { int lin;
instruction_list(&np) char *constr;
{ if (np > patlen) patlen = np; int np, nr;
fputs("\n};\n\n",genc); } :
} [
[ { countpat++;
constraint(&lin) constr = (char *) 0;
{ /* Save the constraint, we need it later on */ fprintf(genc,"struct instr_descr pat%d[] = {\n",
constr = malloc((unsigned)(strlen(buf)+1)); countpat);
strcpy(constr,buf); }
} instruction_list(&np)
]? { if (np > patlen) patlen = np;
PATTERN_SEPARATOR fputs("\n};\n\n",genc);
{ fprintf(genc,"struct instr_descr rep%d[] = {\n", }
countpat); [
} constraint(&lin)
replacement(&nr) { /* Save the constraint, we need it later on */
{ fputs("\n};\n\n",genc);} constr = malloc((unsigned)(strlen(buf)+1));
LINE_TERMINATOR strcpy(constr,buf);
SPACE* }
{ addpattern(constr,lin,np,nr);} ]?
]* PATTERN_SEPARATOR
{ printhashtable(); { fprintf(genc,"struct instr_descr rep%d[] = {\n",
printpatterns(); countpat);
fprintf(genh,"#define NRVARS %d\n",countid); }
fprintf(genh,"#define NRPATTERNS %d\n",countpat); replacement(&nr)
fprintf(genh,"#define MIN_WINDOW_SIZE %d\n", { fputs("\n};\n\n",genc);}
patlen+3); LINE_TERMINATOR
fclose(genh); SPACE*
} { addpattern(constr,lin,np,nr);}
; ]*
{ printhashtable();
instruction_list(int *n;) : printpatterns();
instruction(1) fprintf(genh,"#define NRVARS %d\n",countid);
{ *n = 1;} fprintf(genh,"#define NRPATTERNS %d\n",countpat);
[ fprintf(genh,"#define MIN_WINDOW_SIZE %d\n",
INSTRUCTION_SEPARATOR patlen+3);
{ fputs(",\n",genc);} fclose(genh);
SPACE* }
instruction(0) ;
{ *n += 1;}
]* instruction_list(int *n;) :
; instruction(1)
{ *n = 1;}
instruction(int opt;) [
{ int count = 0;} : INSTRUCTION_SEPARATOR
opcode(opt) { fputs(",\n",genc);}
{ if (strcmp(buf,"ANY") != 0) { SPACE*
fprintf(genc,"\t{\"%s\", {",buf); instruction(0)
} { *n += 1;}
else fputs("\t{(char *) 0, {",genc); ]*
count = 0; ;
}
[ instruction(int opt;)
operand(' ') { int count = 0;} :
{ count = 1;} opcode(opt)
[ { if (strcmp(buf,"ANY") != 0) {
OPERAND_SEPARATOR fprintf(genc,"\t{\"%s\", {",buf);
{ count++;} }
SPACE* else fputs("\t{(char *) 0, {",genc);
operand(',') count = 0;
]* }
{ if (count > maxoperand) { [
error("Too many operands"); operand(' ')
} { count = 1;}
} [
]? OPERAND_SEPARATOR
{ while (count++ < maxoperand) { { count++;}
fprintf(genc,"%c{\"\",-1,\"\"}",count == 1 ? ' ' : ','); SPACE*
} operand(',')
putc('}',genc); ]*
putc('}',genc); { if (count > maxoperand) {
} error("Too many operands","");
; }
}
opcode(int opt;) ]?
{ char *p = buf;} : { while (count++ < maxoperand) {
[ fprintf(genc,"%c{\"\",-1,\"\"}",count == 1 ? ' ' : ',');
[ LETTER }
| DIGIT putc('}',genc);
| OTHER putc('}',genc);
] }
{ *p++ = dot.t_attrib;} ;
]+
SPACE+ opcode(int opt;)
{ *p = '\0'; { char *p = buf;} :
if (opt) addtohashtable(buf,countpat); [
} [ LETTER
; | DIGIT
| OTHER
operand(int c;) ]
{ register struct symtab *p = 0;} : { *p++ = dot.t_attrib;}
{ fprintf(genc, "%c{\"", c);} ]+
[ SPACE+
identifier { *p = '\0';
{ if (!p) { if (opt) addtohashtable(buf,countpat);
p = findident(idbuf,LOOKING,&idtable); }
if (p) fprintf(genc,"\",%d,\"",p->s_num); ;
else fputs(idbuf,genc);
} operand(int c;)
else fputs(idbuf,genc); { register struct symtab *p = 0;} :
} { fprintf(genc, "%c{\"", c);}
| DIGIT [
{ putc(dot.t_attrib,genc);} identifier
| OTHER { if (!p) {
{ putc(dot.t_attrib,genc);} p = findident(idbuf,LOOKING,&idtable);
]+ if (p) fprintf(genc,"\",%d,\"",p->s_num);
{ if (p) fputs("\"}",genc); else fputs(idbuf,genc);
else fputs("\",0,\"\"}",genc); }
} else fputs(idbuf,genc);
SPACE* }
; | DIGIT
{ putc(dot.t_attrib,genc);}
replacement (int *n;) | OTHER
{register i;} : { putc(dot.t_attrib,genc);}
SPACE* ]+
{ *n = 0;} { if (p) fputs("\"}",genc);
[ else fputs("\",0,\"\"}",genc);
instruction(0) }
{ *n = 1;} SPACE*
[ ;
INSTRUCTION_SEPARATOR
{ fputs(",\n", genc);} replacement (int *n;)
SPACE* {register int i;} :
instruction(0) SPACE*
{ *n += 1;} { *n = 0;}
]* [
| /* empty replacement, but there must be a instruction(0)
* structure initializer anyway { *n = 1;}
*/ [
{ fputs("\t{\"\", {",genc); INSTRUCTION_SEPARATOR
for (i = 0; i < maxoperand; i++) { { fputs(",\n", genc);}
fprintf(genc, "%c{\"\",-1,\"\"}",i?',':' '); SPACE*
} instruction(0)
fputs("}}",genc); { *n += 1;}
} ]*
] | /* empty replacement, but there must be a
; * structure initializer anyway
*/
{ fputs("\t{\"\", {",genc);
identifier for (i = 0; i < maxoperand; i++) {
{ char *p = idbuf; } : fprintf(genc, "%c{\"\",-1,\"\"}",i?',':' ');
LETTER }
{ *p++ = dot.t_attrib;} fputs("}}",genc);
[ %while (1) }
LETTER { *p++ = dot.t_attrib;} ]
| DIGIT { *p++ = dot.t_attrib;} ;
]*
{ *p = '\0';}
; identifier
{ char *p = idbuf; } :
separator : LETTER
'%' '%' SPACE* LINE_TERMINATOR { *p++ = dot.t_attrib;}
; [ %while (1)
LETTER { *p++ = dot.t_attrib;}
| DIGIT { *p++ = dot.t_attrib;}
]*
{ *p = '\0';}
;
separator :
'%' '%' SPACE* LINE_TERMINATOR
;