/* cee.fg - Felix Gaertner's first formatted grammar for C * target is LaTeX, built for use with noweb * * $Id: cee.fg,v 1.2 1996/12/16 19:02:09 gaertner Exp $ * * History at end. */ %token BINOP %token UNORBINOP %token QUESTION %token UNOP %token LPAR %token RPAR %token LBRACE %token RBRACE %token LBRACK %token RBRACK %token SEMI %token COLON %token LPROC %token ID %token NUMBER %token INT_LIKE %token CASE_LIKE %token IF_LIKE %token DO_LIKE %token ELSE_LIKE %token TYPEDEF_LIKE %token STRUCT_LIKE %token SIZEOF_LIKE %token DEFINE_LIKE %token COMMA %token INSERT %token STRING %token CHUNK %token IGNORE %{ #include #include #include /* these functions help to typeset typedefs. they implement * a simple lookup table to see if an identifier is a * typedef or what... * * taken from Kernighan/Ritchie: The C Programming Language, p.144ff */ struct nlist { /* a table entry: */ struct nlist *next; /* next entry in chain */ char* name; /* the identifier */ }; #define HASHSIZE 101 static struct nlist* hashtab[HASHSIZE]; /* the hash table */ /* form the hash value of a string */ static unsigned hash(char* s) { // cerr << "hash(" << s << ") called." << endl; unsigned hashval; for (hashval = 0; *s != '\0'; s++) hashval = *s + 31 * hashval; return hashval % HASHSIZE; } /* lookup: look for s in hashtab * * returns a pointer to the found element or NULL if it was not * found. */ static struct nlist* lookup(char* s) { // cerr << "lookup(" << s << ") called." << endl; struct nlist* np; for (np = hashtab[hash(s)]; np != NULL; np = np->next) if (strcmp(s, np->name) == 0) return np; /* found */ return NULL; /* not found */ } /* install: put name in hashtab. * * returns a pointer to the new element if all went well, * returns NULL on error. */ static struct nlist *install(char* name) { // cerr << "install(" << name << ") called." << endl; struct nlist* np; unsigned hashval; if ((np = lookup(name)) == NULL) { /* not found */ np = (struct nlist*) malloc(sizeof(*np)); if (np == NULL || (np->name = strdup(name)) == NULL) return NULL; hashval = hash(name); np->next = hashtab[hashval]; hashtab[hashval] = np; } return np; } /* attibute_to_string - * turn an attribute into a string * * idea: call print() with a strstream * * NB: Output has to be deleted and the strstream properly * terminated before calling .str()! Otherwise, the last * characters are garbeled. */ static char* attribute_to_string( Attribute* a ) { ostrstream printstream; Latex_cweb_output* o = new Latex_cweb_output(printstream); a->print(*o); delete o; printstream << ends; return printstream.str(); } /* forward declaration of debugging function */ static void debug_print( char* this_is, Attribute* stuff ); %} %% // inserting $s for TeX's math mode is quite tricky because // at the beginning of \LA and \RA noweb expects to not be in // math mode and complains about missing $s when we're already in // it. Solution: We'll use Lee's \mathin and \mathout macros to // surround expressions and alike. It's better to selectively invoke // math mode than have everything in it. final : exp { "\\mathin" $1 "\\mathout" } // [ debug_print("Final exp", $1); ] | stmt { $1 } // [ debug_print("Final stmt", $1); ] | error { "syntax error" } ; // get formatting of identifiers right id : ID { [ lookup(attribute_to_string($1)) ? create("{\\bf ") : create("{\\it ") ] $1 "}" } ; // ************************************************************ // format expressions: exp : NUMBER | STRING ; // easy things: // I don't know why I have duplicated everything (exp, id) but // I think it was in order for typedef to work correctly exp : exp UNOP // x++ | id UNOP | UNOP exp // ++x | UNOP id | exp BINOP exp | id BINOP exp | exp BINOP id | id BINOP id | exp UNORBINOP exp | id UNORBINOP exp | exp UNORBINOP id | id UNORBINOP id | UNORBINOP exp // *x | UNORBINOP id | LPAR exp RPAR // (x+1) | LPAR id RPAR | id LBRACK exp RBRACK // a[10] | id LBRACK id RBRACK // a[i] | id LBRACK RBRACK { $1 $2 "\\," $3 } // a[] | id LPAR decl_list RPAR { "\\hbox{" $1 $2 $3 $4 "}" } // f(x+1) f(a,b) | id LPAR RPAR { "\\hbox{" $1 $2 "\\," $3 "}" } // f() ; // ************************************************************** // declarations of variables with or without initializers decl : INT_LIKE decl_list { $1 "\\ " $2 } // int a, b, c | INT_LIKE INT_LIKE decl_list { $1 "\\ " $2 "\\ " $3 } // extern int a | id decl_list { $1 "\\ " $2 } // foo bar ; // lists like in function headings, i.e. f(int i, int b) params_list : decl | decl COMMA params_list { $1 $2 opt9 "\\ " $3 } ; // a sequence of variables (possibly with initializers) decl_like : exp { "\\mathin " $1 "\\mathout " } | id // i ; decl_list : decl_like | decl_like COMMA decl_list { $1 $2 opt9 $3 } ; stmt : decl SEMI // int i; ; // *************************************************************** // typedefs. it's important that the identifier is an ID token and // not an id token (which has italics around it already) typedef : TYPEDEF_LIKE INT_LIKE ID [ install(attribute_to_string($3)); ] { $1 "\\ " $2 "\\ {\\bf " $3 "}" } | TYPEDEF_LIKE INT_LIKE UNORBINOP ID // typedef char* String [ install(attribute_to_string($4)); ] { $1 "\\ " $2 $3 "\\ {\\bf " $4 "}" } ; stmt : typedef SEMI ; // *************************************************************** // statements stmt : exp SEMI { "\\mathin " $1 "\\mathout " $2 } ; // empty block stmt : LBRACE RBRACE { $1 "\\," $2 } | SEMI ; // block statement stmt : LBRACE stmt RBRACE { force $1 indent force $2 outdent force $3 force } ; // ***************************************************************** // control structures // if then / if then else / while / case stmt : IF_LIKE exp stmt { $1 "\\ \\mathin " $2 "\\mathout\\ " $3 } | IF_LIKE exp stmt ELSE_LIKE stmt { $1 "\\ \\mathin " $2 "\\mathout\\ " $3 "\\ " break_space $4 "\\ " $5 } ; // for loops stmt : IF_LIKE LPAR stmt stmt exp RPAR stmt // for (i=1;i<1;i++); { $1 "\\ \\mathin " $2 $3 "\\ " $4 "\\ " $5 $6 "\\mathout\\ " $7 } | IF_LIKE LPAR stmt stmt RPAR stmt // for (;;); { $1 "\\ \\mathin " $2 $3 "\\ " $4 $5 "\\mathout\\ " $6 } ; // do, case etc stmt : DO_LIKE stmt IF_LIKE exp SEMI { $1 $2 $3 "\\ \\mathin " $4 "\\mathout " $5 } | CASE_LIKE SEMI // return; | CASE_LIKE exp SEMI { $1 "\\ \\mathin " $2 "\\mathout " $3 } ; tag : CASE_LIKE COLON // default: | id COLON { "\n@def " $1 "\n" "\\mathin " $1 "\\mathout " $2 } | CASE_LIKE exp COLON { $1 "\\ \\mathin " $2 "\\mathout " $3 } | tag tag { $1 break_space $2 } // 1: 2: ; stmt : tag stmt { force backup $1 "\\ " opt9 $2 } // 1: a=1; ; // join up statements stmt : stmt stmt { $1 force $2 } | stmt SEMI // empty statemet ; // be sure not to be in math mode for chunks stmt : CHUNK SEMI { "\\mathout " $1 $2 force } | CHUNK ; exp : CHUNK { $1 } ; // *********************************************************** // preprocessor directives stmt : LPROC | LPROC stmt | LPROC STRING // #include "abc.h" | LPROC LPROC // #include | INSERT | IGNORE ; // ********************************************************* // do nothing rules for comments and ignores ... %% static void debug_print( char* this_is, Attribute* stuff ) { cerr << "*** " << this_is << ":" << endl; Latex_cweb_output os(cerr); stuff->print(os); } /* * $Log: cee.fg,v $ * Revision 1.2 1996/12/16 19:02:09 gaertner * release version * * Revision 1.1 1996/12/11 17:14:16 gaertner * Initial revision * */