/* * javafx.fg -- experimental Pretzel grammar for Java * * based on original version by Lee Wittenberg and enhanced * for use with noweb and made into a self contained * Pretzel file by Felix Gaertner * * History at end * * $Header: /a/spelunke/export/vol1/gaertner/pretzel/contrib/noweb/java.latex/RCS/javafx.fg,v 1.1 1997/07/09 14:24:27 gaertner Exp $ * */ /* * A word concerning indexing: I couldn't get noweb to typset identifiers * in different fonts in the index. Help on this is very welcome. The * current strategy leaves identifiers unchanged up to the very moment * their final look is determined (i.e. they change from ID_LIKE to * id_like). In this moment, we think about TeX and escape underlines. */ %token BINOP %token BREAK_LIKE %token CASE_LIKE %token CATCH_LIKE %token CHUNK %token CLASS %token COLON %token COMMA %token COMMENT %token DEFAULT_LIKE %token DOT %token DOT_STAR %token DO_LIKE %token ELSE_LIKE %token EXTENDS_LIKE %token FINALLY_LIKE %token FOR_LIKE %token ID_LIKE %token IF_LIKE %token IGNORE %token IMPORT_LIKE %token INCROP %token INT_LIKE %token LBRACE %token LBRACK %token LPAR %token NUM %token QUESTION %token RBRACE %token RBRACK %token RPAR %token SHORT_ID %token SEMI %token STRING %token SYNC_LIKE %token TRY_LIKE %token UNOP %token UNORBINOP %{ #include #include #include #include // for escaped_underlines /* flag to help distinguish betweet declaration and use of an identifier. * It's set to 1 whenever we think we're parsing a declaration. */ static int in_decl = 0; /* forward declarations: */ /* these functions help to typeset classes. They implement * a simple lookup table to see if an identifier is a * class 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 */ }; /* size of hash table. Should be changed if you are working on large * programs. */ #define HASHSIZE 101 static struct nlist* hashtab[HASHSIZE]; /* the hash table */ /* form the hash value of a string */ static unsigned hash(char* s); /* 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); /* 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); /* attibute_to_string - * turn an attribute into a string * */ static char* attribute_to_string( Attribute* a ); // forward declaration of a function that replaces `_' // with `\_' in a copy of s static char* escaped_underlines(char* s); /* debugging function */ static void debug_print( char* this_is, Attribute* stuff ); %} %% final : exp { "\\mathin " $1 "\\mathout" } | decl_list | IGNORE | COMMENT { "\\qquad" break_space $1 force } | IGNORE final | COMMENT final { $1 force $2 } ; decl_list : decl | decl_list decl { $1 force $2 } ; decl : exp block { "\\mathin" $1 "\\mathout\\ " $2 } ; block : lbrace rbrace { $1 force $2 } | lbrace decl_list rbrace { $1 cancel indent force $2 outdent force $3 } ; exp : expr | exp dot expr | exp comma expr { $1 $2 opt3 "\\mathin " $3 } | exp expr { $1 $2 } ; expr : term | expr binop term { $1 opt9 $2 $3 } | expr unorbinop term { $1 opt9 $2 $3 } | expr extends_like idlist { $1 "\\ " opt2 $2 "\\ " $3 } | expr brack_exp ; binop : question exp colon { "\\mathbin{" $1 $2 $3 "}" } ; idlist : ident | idlist comma ident { $1 $2 opt9 $3 } ; // Identifiers come as plain strings from the scanner. // Identifiers that are class names are installed into the lookup table // and typeset in boldface. Also, a `definition' index entry must be // generated. Before typesetting identifiers, underlines must be escaped. // // Another issue is how to distinguish between definition and use? Locally // you can't distinguish whether the id `a' is part of `int a' or `a++'. // We'll try to use a global flag `in_decl' that is set to `true' whenever // we think we're just parsing a declaration. ident : id_like | class ID_LIKE [ install(attribute_to_string($2)); ] { "{\\bf " $1 "}\\ \\mbox{\\bf " [ create(escaped_underlines(attribute_to_string($2))) ] "}" "%\n@index defn " $2 "\n" } | class SHORT_ID [ install(attribute_to_string($2)); ] { "{\\bf " $1 "}\\ \\mbox{\\bf " [ create(escaped_underlines(attribute_to_string($2))) ] "}" "%\n@index defn " $2 "\n" } | INT_LIKE class ID_LIKE [ install(attribute_to_string($3)); ] { $1 "\\ {\\bf " $2 "}\\ \\mbox{\\bf " [ create(escaped_underlines(attribute_to_string($3))) ] "}" "%\n@index defn " $3 "\n" } | INT_LIKE class SHORT_ID [ install(attribute_to_string($3)); ] { $1 "\\ {\\bf " $2 "}\\ \\mbox{\\bf " [ create(escaped_underlines(attribute_to_string($3))) ] "}" "%\n@index defn " $3 "\n" } | sync_like id_like { $1 "\\ " $2 } | ident id_like { $1 "\\ " $2 } ; brack_exp : lbrack rbrack { $1 "\\thinspace " $2 } | lbrack exp rbrack | brack_exp ident { $1 "\\ " $2 } ; term : factor | unop term { "\\mathin " $1 $2 } | unorbinop term { "\\mathin " $1 $2 } | incrop term { "\\mathin " $1 $2 } | term incrop { "\\mathin " $1 $2 } ; factor : ident | num | string | lpar rpar { $1 "\\thinspace" $2 } | lpar exp rpar ; decl : block | non_block_stmt ; non_block_stmt : semi { cancel $1 } | exp semi { "\\mathin " $1 "\\mathout" $2 } | break_like semi | break_like exp semi { $1 "\\ \\mathin " $2 "\\mathout" $3 } | sync_like lpar exp rpar decl { $1 "\\ \\mathin " $2 $3 $4 "\\mathout\\ " $5 } | import_head semi | label colon decl { force backup $1 $2 force $3 } | try_stmt | if_block | if_simple | else_head block { $1 "\\ " $2 } | else_head non_block_stmt { $1 indent force $2 outdent } | for_stmt | do_stmt ; import_head : import_like id_like { $1 "\\ " $2 } | import_head dot id_like | import_head dot_star ; if_head : if_like lpar exp rpar { $1 "\\ \\mathin " $2 $3 $4 "\\mathout" } ; if_block : if_head block { $1 "\\ " $2 } ; if_simple : if_head non_block_stmt { $1 indent force $2 outdent } ; else_head : else_like | if_block else_like { $1 "\\ " $2 } | if_simple else_like { $1 force $2 } ; try_stmt : try_like block { $1 "\\ " $2 } | try_stmt finally_like block { $1 "\\ " $2 "\\ " $3 } | try_stmt catch_like lpar exp rpar block { $1 "\\ \\mathin " $2 $3 $4 $5 "\\mathout\\ " $6 } ; label : default_like | case_like exp { $1 "\\ \\mathin " $2 "\\mathout"} | id_like ; do_stmt : do_like block if_head semi { $1 "\\ " $2 "\\ " $3 $4 } | do_like non_block_stmt if_head semi { $1 indent force $2 outdent $3 $4 } ; for_head : for_like lpar for_control rpar { $1 "\\ " $2 $3 $4 } ; for_control : opt_exp semi opt_exp semi opt_exp ; opt_exp : // empty | exp { "\\mathin " $1 "\\mathout" } ; for_stmt : for_head block { $1 "\\ " $2 } | for_head non_block_stmt { $1 indent force $2 outdent } ; // rules to pass comments and ignores through unnoticed binop : BINOP | binop IGNORE | binop COMMENT { $1 "\\qquad" break_space $2 force } ; break_like : BREAK_LIKE | break_like IGNORE | break_like COMMENT { $1 "\\qquad" break_space $2 force } ; case_like : CASE_LIKE | case_like IGNORE | case_like COMMENT { $1 "\\qquad" break_space $2 force } ; catch_like : CATCH_LIKE | catch_like IGNORE | catch_like COMMENT { $1 "\\qquad" break_space $2 force } ; class : CLASS | class IGNORE | class COMMENT { $1 "\\qquad" break_space $2 force } ; colon : COLON | colon IGNORE | colon COMMENT { $1 "\\qquad" break_space $2 force } ; comma : COMMA | comma IGNORE | comma COMMENT { $1 "\\qquad" break_space $2 force } ; default_like : DEFAULT_LIKE | default_like IGNORE | default_like COMMENT { $1 "\\qquad" break_space $2 force } ; dot : DOT | dot IGNORE | dot COMMENT { $1 "\\qquad" break_space $2 force } ; dot_star : DOT_STAR | dot_star IGNORE | dot_star COMMENT { $1 "\\qquad" break_space $2 force } ; do_like : DO_LIKE | do_like IGNORE | do_like COMMENT { $1 "\\qquad" break_space $2 force } ; else_like : ELSE_LIKE | else_like IGNORE | else_like COMMENT { $1 "\\qquad" break_space $2 force } ; extends_like : EXTENDS_LIKE | extends_like IGNORE | extends_like COMMENT { $1 "\\qquad" break_space $2 force } ; finally_like : FINALLY_LIKE | finally_like IGNORE | finally_like COMMENT { $1 "\\qquad" break_space $2 force } ; for_like : FOR_LIKE | for_like IGNORE | for_like COMMENT { $1 "\\qquad" break_space $2 force } ; // here we come across an identifier that's not part of a // `class' or `interface' clause. If it's in the lookup // table then it has already been defined as a class or // interface and so it looks like we're dealing with // a declaration now. // // If it's not in the table, it's got to be in italics and // the index entry depends on the `in_decl' flag. id_like : ID_LIKE { // begin index entry "%\n@index " [ (in_decl == 0) ? create("use ") : create("defn ") ] $1 "\n" // end index entry [ lookup(attribute_to_string($1)) ? create("{\\bf ") : create("{\\it ") ] [create(escaped_underlines(attribute_to_string($1)))] "}" } // don't index short ids but still put correct markup around them: | SHORT_ID { "{" [ lookup(attribute_to_string($1)) ? create("\\bf") : create("\\it") ] " " [create(escaped_underlines(attribute_to_string($1)))] "}" } | CHUNK { $1 force } | id_like IGNORE | id_like COMMENT { $1 "\\qquad" break_space $2 force } ; if_like : IF_LIKE | if_like IGNORE | if_like COMMENT { $1 "\\qquad" break_space $2 force } ; import_like : IMPORT_LIKE | import_like IGNORE | import_like COMMENT { $1 "\\qquad" break_space $2 force } ; incrop : INCROP | incrop IGNORE | incrop COMMENT { $1 "\\qquad" break_space $2 force } ; // INT_LIKE's become id_like, but it looks like a declaration now id_like : INT_LIKE [ in_decl = 1; ] { $1 } ; lbrace : LBRACE | lbrace IGNORE | lbrace COMMENT { $1 "\\qquad" break_space $2 force } ; lbrack : LBRACK | lbrack IGNORE | lbrack COMMENT { $1 "\\qquad" break_space $2 force } ; lpar : LPAR | lpar IGNORE | lpar COMMENT { $1 "\\qquad" break_space $2 force } ; num : NUM | num IGNORE | num COMMENT { $1 "\\qquad" break_space $2 force } ; question : QUESTION | question IGNORE | question COMMENT { $1 "\\qquad" break_space $2 force } ; rbrace : RBRACE | rbrace IGNORE | rbrace COMMENT { $1 "\\qquad" break_space $2 force } ; rbrack : RBRACK | rbrack IGNORE | rbrack COMMENT { $1 "\\qquad" break_space $2 force } ; rpar : RPAR | rpar IGNORE | rpar COMMENT { $1 "\\qquad" break_space $2 force } ; // a semicolon seems to end a declaration semi : SEMI [ in_decl = 0; ] { $1 } | semi IGNORE | semi COMMENT { $1 "\\qquad" break_space $2 force } ; string : STRING | string IGNORE | string COMMENT { $1 "\\qquad" break_space $2 force } ; sync_like : SYNC_LIKE | sync_like IGNORE | sync_like COMMENT { $1 "\\qquad" break_space $2 force } ; try_like : TRY_LIKE | try_like IGNORE | try_like COMMENT { $1 "\\qquad" break_space $2 force } ; unop : UNOP | unop IGNORE | unop COMMENT { $1 "\\qquad" break_space $2 force } ; unorbinop : UNORBINOP | unorbinop IGNORE | unorbinop COMMENT { $1 "\\qquad" break_space $2 force } ; %% /* these functions help to typeset classes. They implement * a simple lookup table to see if an identifier is a * class or what... * * taken from Kernighan/Ritchie: The C Programming Language, p.144ff */ /* 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 ) { // cerr << "entering attribute to string." << endl; // debug_print("attribute is", a); ostrstream printstream; Latex_cweb_output* o = new Latex_cweb_output(printstream); // o->debug_on(); a->print(*o); delete o; printstream << ends; char* tmp = printstream.str(); //cerr << "attribute to string returning `" << tmp << "'." << endl; return tmp; } // escaped_underines replaces every occurrence of `_' by // the two characters `\_' in a copy of the string pointed to // by s // // the implementation first counts the number of underlines in // the string s and allocates new memory for the string. It then // copies the string byte after byte into the new place and // takes care to insert a `\' before any underline. // // this is a bit dirty as we don't have a chance to free the // allocated space later on, but it's still better than messing // around with yytext. To minimize the amount of memory I have // added a test whether copying is needed or not. static char* escaped_underlines(char* s) { // cerr << "entering escaped underlines with `" << s << "'." << endl; char* tmp = s; int number_of_ul = 0; int left = 0; // s[left] is the next char to copy int right = 0; // place s[left] in tmp[right] // fprintf(stderr, "call of escaped_underlines\n"); // count underlines in s while (*tmp != 0) { if (*tmp == '_') number_of_ul++; tmp++; } // fprintf(stderr, "escaped_underlines: Number of ul's in %s is %d\n", s, number_of_ul); if (number_of_ul == 0) { tmp = s; // skip copying } else { tmp = new char[strlen(s) + number_of_ul + 1]; assert(tmp!=NULL); // now start to copy while (s[left] != 0) { // should be `!= NULL', shouldn,t it, but // some compilers choke on it if (s[left] == '_') { tmp[right] = '\\'; right++; } tmp[right] = s[left]; left++; right++; } tmp[right] = s[left]; /* terminate string */ } // cerr << "escaped underlines returning `" << tmp << "'." << endl; return(tmp); } /* debugging function */ static void debug_print( char* this_is, Attribute* stuff ) { cerr << "*** " << this_is << ":" << endl; Latex_cweb_output os(cerr); stuff->print(os); } /* * $Log: javafx.fg,v $ * Revision 1.1 1997/07/09 14:24:27 gaertner * Initial revision * * Revision 1.3 1997/07/08 19:08:10 theedge * small additions to commmentary * * Revision 1.2 1997/07/08 18:48:34 theedge * Versions that work. * * Revision 1.1 1997/06/26 16:23:56 theedge * Initial revision * */