emery@siemens.UUCP (05/02/85)
<<eat me, you line eater>> We use Scribe as our standard word processing system. We needed a way to present Ada code within some text. The Ada Language Reference Manual has defined a presentation style for Ada code, with reserved words in lower-case/boldface. We wanted to use this style, and add other changes to make the code more readable. In particular, we wanted to set comments off from Ada code. Finally, we wanted to do this without having to modify our Ada code by hand. To meet these requirements, we developed a tool called "adaform". "adaform" is a UNIX filter that accepts (well formed) Ada programs from stdin, and adds Scribe commands. The output is then suitable for 'Scribing'. See the implementation section for a definition of the Scribe environmnents used by adaform. Invocation is "adaform < <your input> > <your output>". You must direct input from standard input; adaform does not recognize the convention that a filename may be passed as a parameter for standard input. The following is straight text, of 3 parts: The first is a description of the tool, followed by the LEX file, followed by our C driver program. Capabilities: adaform does the following things: 1. Ada reserved words are printed in boldface. 2. Ada comments are printed in italics. 3. Comment reserved words (such as pre-conditions, history, etc.) are printed in bold italics. 4. Pragma page is recognized; a new page is started after this pragma. Additionally, every library unit is started on a new page (triggered by an Ada 'with' clause.) 5. Package, procedure, function, type, subtype and task names are indexed. The index entry is the identifier, followed by the Ada thing identified. Additionally, if you use the LibraryFile MultiLevelIndex, then there is a secondary index by the class of item. for instance: Foo, package 2 Fred, type 1 Frog, type 3 Fubar, task 3 package Foo 2 task Fubar 3 Fred 1 Frog 3 6. A 'hinge' is placed on each blank line. This means that a group of non-blank lines will be kept on one page. An example of this is a function declaration and its comments. Limitations: adaform expects legal Ada code. It has no error handling, and its actions on an ill-formed program are undefined, and will probably either give you a lex error, or garbage. The logic used to detect a new compilation unit is very primitive. If adaform finds a with clause (that is not in a generic declaration), it first inserts a page feed (@newpage). Lines preceeding the with clause will be placed on the preceeding page. If there is more than one compilation unit in a package, and they do not have with clauses, then they will not start on a new page. The rule of thumb here is first, use only 1 compilation unit per text file, and second, don't use preceeding comments. If a set of non-blank lines exceeds a single page, Scribe will probably issue an error message. Use "pragma page" to establish page breaks. The only 'prettyprinting' performed by adaform is that reserved words are translated to lower case, except for EXIT, RETURN, RAISE and GOTO. Adaform performs no formatting. However, tabs are converted to the scribe tab character "@\". Because the output from Scribe is in proportionally spaced fonts, column alignment is not preserved. This is most noticable when you have a comment like: ---------------------------------- -- Here is my comment -- ---------------------------------- This usually comes out looking something like: ----------------------- -- Here is my comment -- ----------------------- due to the different character widths of the text and the '-' character. To insure indentation alignment, use tabs instead of spaces. Implementation: adaform was created using Lex and Herm Fischer's Lex input for his Ada grammar. Because it is 'lexed', and I'm not a Lexpert, it runs a little slowly. A driver is also requred for the Lex output, this driver writes out the environment standards, and then calls yylex(). There are 4 Scribe definitions needed to support adaform. These are definitions of the various Scribe environments used by adaform: @define(AdaResWord=B) makes reserved words all boldface @define(AdaComment=I) comments are in italics @define(AdaCommentWord=P) special comment reserved words in bold italics @define(AdaCode=example, FaceCode R, LeftMargin 0, RightMargin 0, font SmallBodyFont, BlankLines=HingeKeep) AdaCode is an example environment, with no indentation, using roman (standard) type, in the SmallBodyFont (10 point), and simulates a hinge command at each blank line. These definitions are usually written out by the driver. Future Features: I hope to add scope information to the index entries, so the following will be the result: Foo, type, defined in Ralph.Bar 3 Fred, function, defined in Ralph 2 It would be nice to make adaform more intelligent about when to start a new page. Finally, in conjunction with a conventional prettyprinter, I hope to solve the alignment problem when using porportional spaced fonts. Send bugs (hopefully with fixes) to: Dave Emery uucp: ...princeton!siemens!emery arpa: "siemens!emery"@topaz us mail: Siemens Research 105 College Rd East Princeton, NJ 08540 ma bell: (609) 734-6568 trademarks: Ada is a trademark of U.S. Government, AJPO. Scribe is a trademark of Unilogic, Inc. UNIX is a trademark of ATT Bell Labs. LEX DEFINITION %{ /**************************************************************************/ /* Ada for SCRIBE PRINTER */ /**************************************************************************/ /*------------------------------------------------------------------------*/ /* Lexical input for LEX for LALR(1) Grammar for ANSI Ada */ /* */ /* Herman Fischer */ /* Litton Data Systems */ /* March 26, 1984 */ /* */ /*------------------------------------------------------------------------*/ int my_start = 0; /* indicates that it's startup time */ int ignore_next_subprog = 0; /* when in a generic parameter */ /* declaration, indicates that */ /* the next subprogram is a */ /* formal parameter, and not */ /* the actual generic thing. */ int funct_defn = 0; /* indicates that this return is part */ /* of a function declaration, and should */ /* not be capitalized */ char class[20]; #include "stdio.h" #include "ctype.h" %} %e 3500 /* tree nodes array size */ %p 9500 /* positions */ %a 10000 /* transitions array size */ %k 500 /* packed character classes */ %o 10000 /* output array size */ %n 2000 /* states ?! */ %START IDENT Z COMMENT OTHERCMT PRAGMA KEEPNAME GENERICSPEC %% {BEGIN Z;} <Z,IDENT>(ABORT|abort)|(ABS|abs)|(ACCEPT|accept)|(ACCESS|access) | <Z,IDENT>(ALL|all)|(AND|and)|(ARRAY|array)|(AT|at) | <Z,IDENT>(BEGIN|begin)|(BODY|body)|(CASE|case)|(CONSTANT|constant) | <Z,IDENT>(DECLARE|declare)|(DELAY|delay)|(DELTA|delta)|(DIGITS|digits) | <Z,IDENT>(DO|do)|(ELSE|else)|(ELSIF|elsif)|(END|end)|(ENTRY|entry) | <Z,IDENT>(EXCEPTION|exception)|(FOR|for) | <Z,IDENT>(IF|if)|(IN|in)|(IS|is)|(LIMITED|limited)|(LOOP|loop) | <Z,IDENT>(MOD|mod)|(NEW|new)|(NOT|not)|(NULL|null)|(OF|of)|(OR|or) | <Z,IDENT>(OTHERS|others)|(OUT|out)|(PRIVATE|private) | <Z,IDENT>(RANGE|range)|(RECORD|record)|(REM|rem) | <Z,IDENT>(RENAMES|renames)|(REVERSE|reverse) | <Z,IDENT>(SELECT|select)|(SEPARATE|separate) | <Z,IDENT>(TERMINATE|terminate)|(THEN|then)|(USE|use) | <Z,IDENT>(WHEN|when)|(WHILE|while)|(XOR|xor) { MAKELOWER(yytext); hilite(yytext); BEGIN Z; } <Z,IDENT>(WITH|with) { printf("\n@newpage\n"); MAKELOWER(yytext); hilite(yytext); BEGIN Z; } <Z,IDENT>(GOTO|goto)|(EXIT|exit)|(RAISE|raise) { MAKEUPPER(yytext); hilite(yytext); BEGIN Z; } <Z,IDENT>(RETURN|return) { if (funct_defn) funct_defn = 0; else {MAKEUPPER(yytext); funct_defn = 0;}; hilite(yytext); BEGIN Z; } <Z,IDENT>("=>")|("..")|("**")|(":=")|("/=")|(">=")|("<=")|("<<") | <Z,IDENT>(">>")|("<>")|("&")|("(")|("*")|("+")|(",")|("-")|(".") | <Z,IDENT>("/")|(":")|(";")|("<")|("=")|(">")|("|") { ECHO; BEGIN Z; } <Z,IDENT>")" {ECHO; BEGIN IDENT;} "\t" {unput('\\'); unput('@');} <Z,IDENT>(PRAGMA|pragma) { MAKELOWER(yytext); hilite(yytext); BEGIN PRAGMA; } <PRAGMA>[" "(@\\)]+(PAGE|page)[ (@\\)]*; { ECHO; printf("\n@newpage\n"); BEGIN Z; } <PRAGMA>. { unput(yytext[0]); BEGIN Z; } <Z,IDENT>TYPE|type | <Z,IDENT>SUBTYPE|subtype | <Z,IDENT>TASK|task | <Z,IDENT>(PROCEDURE|procedure) | <Z,IDENT>(PACKAGE|package) { MAKELOWER(yytext); hilite(yytext); strcpy(class, yytext); BEGIN KEEPNAME;} <Z,IDENT>(FUNCTION|function) { MAKELOWER(yytext); hilite(yytext); strcpy(class, yytext); funct_defn = 1; BEGIN KEEPNAME;} <KEEPNAME>[a-zA-Z][a-z_A-Z0-9]* { ECHO; printf("@index(%s, %s)", yytext, class); printf("@indexsecondary(primary=%s, secondary=%s)", class, yytext); BEGIN Z;} <Z,IDENT>(GENERIC|generic) { MAKELOWER(yytext); hilite(yytext); BEGIN GENERICSPEC;} <GENERICSPEC>(WITH|with) { MAKELOWER(yytext); hilite(yytext); ignore_next_subprog = 1;} <GENERICSPEC>(PROCEDURE|procedure)|(FUNCTION|function) { MAKELOWER(yytext); hilite(yytext); {if (ignore_next_subprog) ignore_next_subprog = 0; else { {if (strcmp(yytext,"procedure")) strcpy(class,"generic procedure"); else strcpy(class,"generic function"); funct_defn = 1; }; ignore_next_subprog = 0; BEGIN KEEPNAME; }; }; } <GENERICSPEC>(PACKAGE|package) { MAKELOWER(yytext); hilite(yytext); strcpy(class,"generic package"); BEGIN KEEPNAME;} <GENERICSPEC>(ACCESS|access)|(ARRAY|array)|(CONSTANT|constant) | <GENERICSPEC>(DELTA|delta)|(DIGITS|digits)|(IN|in)|(IS|is) | <GENERICSPEC>(LIMITED|limited)|(OF|of)|(OTHERS|others)|(OUT|out) | <GENERICSPEC>(PRIVATE|private)|(RANGE|range)|(RETURN|return) | <GENERICSPEC>(SUBTYPE|subtype)|(TYPE|type) { MAKELOWER(yytext); hilite(yytext); } <GENERICSPEC>[a-zA-Z][a-z_A-Z0-9]* {ECHO;} <GENERICSPEC>. {ECHO;} <IDENT>\' {ECHO; BEGIN Z;} /* type mark only */ <Z,IDENT>[a-zA-Z][a-z_A-Z0-9]* {ECHO; BEGIN IDENT; } <Z,IDENT>[0-9][0-9_]*([.][0-9_]+)?([Ee][-+]?[0-9_]+)? { ECHO; BEGIN Z; } <Z,IDENT>[0-9][0-9_]*#[0-9a-fA-F_]+([.][0-9a-fA-F_]+)?#([Ee][-+]?[0-9_]+)? { ECHO; BEGIN Z; } <Z,IDENT>\"([^\"]*(\"\")*)*\" {ECHO; BEGIN Z; } <Z>\'([^\']|\'\')\' {ECHO; BEGIN Z; } <Z,IDENT>[" "(@\\)] {ECHO;} /* ignore spaces and tabs */ <Z,IDENT>. {ECHO; printf("?? lexical error [%s] ??\n(@\\)", yytext);} <Z,IDENT>"--"([" "(@\\)]*) {ECHO; BEGIN COMMENT;} <COMMENT,OTHERCMT>"-"+ {ECHO;} <COMMENT,OTHERCMT>[\n] {ECHO; BEGIN Z;} <COMMENT>(("Function"[" "(@\\)]*":")|("Reference"[" "(@\\)]*":")) | <COMMENT>(("History"[" "(@\\)]*":")|("Exceptions"[" "(@\\)]*":")) | <COMMENT>(("Authorization"[" "(@\\)]*":")|("Pre-conditions"[" "(@\\)]*":")) | <COMMENT>(("Post-conditions"[" "(@\\)]*":")|("EXCEPTIONS"[" "(@\\)]*":")) { printf("@AdaCommentWord(%s)", yytext); BEGIN OTHERCMT; } <COMMENT>. { unput(yytext[0]); BEGIN OTHERCMT; } <OTHERCMT>.* { printf("@begin(AdaComment)%s@end(AdaComment)", yytext); BEGIN Z; } %% hilite(it) char *it; {printf("@AdaResWord(%s)", it);} MAKEUPPER(s) char *s; { for (; *s != NULL; ++s) *s = (islower(*s) ? toupper(*s) : *s); } MAKELOWER(s) char *s; { for (; *s != NULL; ++s) *s = (isupper(*s) ? tolower(*s) : *s); } end of LEX DEFINITION OUR DRIVER: main() { printf("@comment(formatted with adaform v 1.3)\n"); printf("@define(AdaResWord=B)\n"); printf("@define(AdaComment=I)\n"); printf("@define(AdaCommentWord=P)\n"); printf("@define(AdaCode=example, FaceCode R, LeftMargin 0, RightMargin 0,\n"); printf("\t font SmallBodyFont, blanklines=hingekeep)\n"); printf("@begin(AdaCode)\n"); printf("@TabClear\n@TabDivide(10)\n"); yylex(); printf("@end(AdaCode)\n"); } end of OUR DRIVER