barad@brand.UUCP (Herb Barad) (05/01/87)
After MANY requests for stLgrind, I am submitting this to the net. I am submitting this directly to this newsgroup (instead of net.sources) since many of the readers of this group do not read net.sources (and even indicated this in their requests). Also, many net.sources readers could care less about Smalltalk or LaTeX. This is stLgrind. This is a tool that will convert Smalltalk-80 fileOut files into LaTeX files. Please report any bugs to me. Note that you might have to rebuild LaTeX to extend some of the parameters (such as save_size) if your methods become too large with too many levels of indentation. I mention this in the manual page. This program is a hacked-up version of stgrind (a Berkeley tool to convert fileOut into troff). I plan future enhancements, but don't hold your breath. (as I need to graduate some day...) Herb Barad #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # Makefile # stLgrind.1 # stLgrind.c # This archive created: Fri Apr 17 16:01:47 1987 export PATH; PATH=/bin:$PATH echo shar: extracting "'README'" '(685 characters)' if test -f 'README' then echo shar: will not over-write existing file "'README'" else sed 's/^ X//' << \SHAR_EOF > 'README' XThis is stLgrind. This tool is very useful to create LaTeX formatted Xversions of Smalltalk-80 source code. The Smalltalk-80 source comes Xfrom the fileOut command. X XBeside the Berkeley Smalltalk project (whose stgrind program was used Xas a skeleton for stLgrind), I would like to thank Ralph Johnson X(johnson@p.cs.uiuc.edu) for some suggestions and fixes. X XGood Luck. X XHerb Barad [USC - Signal and Image Processing Institute] X XUSENET: ...!sdcrdcf!usc-oberon!brand!barad or X ...!mcvax!seismo!sdcsvax!sdcrdcf!usc-oberon!brand!barad X XARPANET: barad@brand.usc.edu X XUSMail: Univ. of Southern California X Powell Hall 306, MC-0272 X Los Angeles, CA 90089-0272 X phone: (213) 743-0911 X SHAR_EOF if test 685 -ne "`wc -c < 'README'`" then echo shar: error transmitting "'README'" '(should have been 685 characters)' fi fi # end of overwriting check echo shar: extracting "'Makefile'" '(257 characters)' if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else sed 's/^ X//' << \SHAR_EOF > 'Makefile' X#Use -g flag for debugging XCFLAGS = -O -s X#CFLAGS = -g XBIN = /usr/local/bin XMAN = /usr/local/man/man1 X XstLgrind: stLgrind.c X cc $(CFLAGS) -o stLgrind stLgrind.c X Xinstall: stLgrind stLgrind.1 X cp stLgrind $(BIN) X cp stLgrind.1 $(MAN) X Xclean: X rm -f stLgrind SHAR_EOF if test 257 -ne "`wc -c < 'Makefile'`" then echo shar: error transmitting "'Makefile'" '(should have been 257 characters)' fi fi # end of overwriting check echo shar: extracting "'stLgrind.1'" '(1330 characters)' if test -f 'stLgrind.1' then echo shar: will not over-write existing file "'stLgrind.1'" else sed 's/^ X//' << \SHAR_EOF > 'stLgrind.1' X.\" $Header: stLgrind.1,v 1.1 87/04/17 15:57:33 barad Stab $ X.TH stLgrind 1 X.SH NAME XstLgrind - convert fileOut formatted files into LaTeX source files X.SH SYNOPSIS X.B stLgrind filename.st > filename.tex X.SH DESCRIPTION XThis program will convert files created by the fileOut command of XSmalltalk-80 into files suitable for LaTeX processing. The input Xfilename is given on the command line as the only argument. The Xoutput LaTeX code is sent to the standard output. X XThis program is similar to the stgrind program that was created for XBerkeley Smalltalk. The program stgrind would create troff output Xfrom a fileOut file. X.SH AUTHOR X.br XHerb Barad X.br XUSC Signal and Image Processing Inst. X.br XPHE 306; MC-0272 X.br XLos Angeles, CA 90089-0272 X.br X X.br Xbarad@brand.usc.edu X.SH BUGS XThe files produced by this program can sometimes exceed the default Xcapacity for TeX (and LaTeX). If needed, you will have to remake tex Xand latex with the parameter save_size increased. As distributed, it Xis set to 600. The maximum value that this may take on is equal to Xthe largest integer you can make from half a word size. For example, Xa 32-bit machine has a halfword size of 16 bits. The maximum value Xfor save_size can therefore be 65535. A value of 6000 is usually Xplenty large. X.br XOnly handles a finite amount of tabbing per line. SHAR_EOF if test 1330 -ne "`wc -c < 'stLgrind.1'`" then echo shar: error transmitting "'stLgrind.1'" '(should have been 1330 characters)' fi fi # end of overwriting check echo shar: extracting "'stLgrind.c'" '(14342 characters)' if test -f 'stLgrind.c' then echo shar: will not over-write existing file "'stLgrind.c'" else sed 's/^ X//' << \SHAR_EOF > 'stLgrind.c' Xstatic char rcsId[] = "$Header: stLgrind.c,v 1.6 87/04/17 15:47:24 barad Stab $"; X X/* X * stLgrind -- converts Smalltalk ``fileOut'' files to LaTeX format X * X * Herb Barad [USC - Signal and Image Processing Institute] X * X * USENET: ...!sdcrdcf!usc-oberon!brand!barad or X * ...!mcvax!seismo!sdcsvax!sdcrdcf!usc-oberon!brand!barad X * X * ARPANET: barad%brand.usc.edu X * X * USMail: Univ. of Southern California X * Powell Hall 306, MC-0272 X * Los Angeles, CA 90089-0272 X * phone: (213) 743-0911 X * X * X * with lots of help from Ralph Johnson X * johnson@p.cs.uiuc.edu X * X * Usage: stLgrind file.st > file.tex ; latex file X * X * NOTE: much of this codes comes from stgrind, a tool from the Berkeley X * Smalltalk project. X */ X X# include <stdio.h> X# include <ctype.h> X X# define FALSE 0 X# define TRUE (~FALSE) X Xchar filename[BUFSIZ]; /* current input file name */ XFILE *infp; X Xtypedef int boolean; X X# define EXPRLEN 10000 Xchar buf[EXPRLEN]; /* stores fileOut expressions */ Xint bp; X Xboolean isTimeStamp(), isComment(), isDefinition(), isClassDefinition(), X isClassComment(), isMethodsFor(), isDoIt(), X getNextExpr(), checkWord(); X Xint bufIndex(); X Xvoid scanTimeStamp(), scanComment(), scanDefinition(), scanClassComment(), X scanClassDefinition(), scanMethodsFor(), scanMethod(), scanDoIt(), X extractWord(), fatal(), getargs(); X Xchar *date(); X X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X getargs(argc, argv); X X printf("\\documentstyle{article}\n"); X printf("\\if@twoside\n\\oddsidemargin 34pt\n\\evensidemargin 72pt\n"); X printf("\\textheight 600pt\n\\topmargin 0pt\n"); X printf("\\marginparwidth 97pt\n\\else\\oddsidemargin 30 pt\n"); X printf("\\evensidemargin 30 pt\n\\marginparwidth 80pt\n\\fi\n"); X printf("\\textwidth 400 pt\n"); X printf("\\parindent 0pt\n\n"); X printf("\\pagestyle{myheadings}\n"); X printf("\\begin{document}\n"); X printf("\\markright{Listing from {\\it %s\\/} at {\\it %s\\/}}\n", X filename, date()); X printf("\\thispagestyle{empty}"); X X while (getNextExpr(infp)) { X if (isTimeStamp()) X scanTimeStamp(); X else if (isComment()) X scanComment(); X else if (isClassComment()) X scanClassComment(); X else if (isClassDefinition()) X scanClassDefinition(); X else if (isDefinition()) X scanDefinition(); X else if (isMethodsFor()) X scanMethodsFor(); X else if (isDoIt()) X scanDoIt(); X else X scanMethod(); X } X printf("\n\\end{document}\n"); X} X X X/* X * Finite state machine to read an expression at a time. X * An expression is X * !string! X * string! X * string! ! X * where string may contain carriage returns. Could have used X * lex, but the carriage returns will be nasty. X * Returns TRUE if an expression has been read successfully. X * Returns FALSE on eof. X * Expression read is stored in the global variable "buf". X * Doesn't check for buffer overflow. X */ X Xboolean XgetNextExpr(fp) XFILE *fp; X{ X register char ch; X register int state; X X /* X * State names for FSM scanner X */ X X# define ST_START 0 X# define ST_1 1 X# define ST_2 2 X# define ST_3 3 X# define ST_4 4 X# define ST_STOP 99999 X X# define getNextChar(ch, fp)\ X if ((ch = getc(fp)) == EOF)\ X return(FALSE);\ X else X X X while ((ch = getc(fp)) != EOF) /* skip all blanks */ X if (ch == EOF) X return(FALSE); X else if (!isspace(ch)) X break; X X bp = 0; X state = ST_START; X X while (state != ST_STOP) { X switch (state) { X case ST_START: X buf[bp++] = ch; X state = ch == '!' ? ST_1 : ST_2; X getNextChar(ch, fp); X break; X case ST_1: X buf[bp++] = ch; X if (ch == '!') X state = ST_STOP; X else X getNextChar(ch, fp); X break; X case ST_2: X buf[bp++] = ch; X if (ch == '!') X state = ST_3; X getNextChar(ch, fp); X break; X case ST_3: X if (ch == '!') { X state = ST_2; X getNextChar(ch, fp); X } X else if (ch == ' ') { X state = ST_4; X getNextChar(ch, fp); X } X else { X state = ST_STOP; X ungetc(ch, fp); X } X break; X case ST_4: X if (ch == '!') { X buf[bp++] = ' '; X buf[bp++] = '!'; X } X else X ungetc(ch, fp); X state = ST_STOP; X break; X default: X fatal("getNextExpr: unknown state: %d", state); X break; X } X } X buf[bp] = '\0'; X return(TRUE); X} X X X/* X * Reports fatal error and die. X */ X Xvoid Xfatal(fmt, s1, s2, s3, s4) Xchar *fmt; Xint s1, s2, s3, s4; X{ X char strbuf[BUFSIZ]; X X sprintf(strbuf, fmt, s1, s2, s3, s4); X fprintf(stderr, "%s\n", strbuf); X exit(1); X} X X X/* X * The following messages classifies a fileOut expression using X * various heuristics. Returns TRUE if the expression in "buf" X * is of a given type. X */ X X/* X * Detects doIt's (e.g. Class initialize!) X */ X Xboolean XisDoIt() X{ X return(isupper(*buf) && buf[bp - 2] != ' ' X && buf[bp - 1] == '!'); X} X X X/* X * Detects the time stamp, which looks like X * 'date and version'! X * from Smalltalk. Not always correct. X */ X Xboolean XisTimeStamp() X{ X return(*buf == '\''); X} X X X/* X * Detects a comment. ("....."!) X */ X Xboolean XisComment() X{ X return(*buf == '"'); X} X X X/* X * Detects the definition of a new class. X */ X Xboolean XisDefinition() X{ X return(checkWord(2, "subclass:") X || checkWord(2, "variableSubclass:") X || checkWord(2, "variableByteSubclass:") X || checkWord(2, "variableWordSubclass:")); X} X X X/* X * Detects this, X * Date comment: 'This is a comment'! X */ X Xboolean XisClassComment() X{ X return(checkWord(2, "comment:")); X} X X X/* X * !Class methodsFor: 'controlling'! X */ X Xboolean XisMethodsFor() X{ X return(*buf == '!'); X} X X X/* X * Definition of a class. X * Class class instanceVariables: ''....! X */ X Xboolean XisClassDefinition() X{ X return(checkWord(2, "class") X && checkWord(3, "instanceVariableNames:")); X} X X X X/* X * The following messages looks at the contents of "buf", X * decodes it, and outputs the contents. X */ X Xvoid XscanDoIt() X{ X register int i; X X for (i = 0; buf[i] != '!'; i++) X putchar(buf[i]); X printf(" {\\bf doIt}\n"); X} X X Xvoid XscanClassDefinition() X{ X int i; X X printf("\n\\begin{verbatim}\n"); X for (i = 0; buf[i] != '!'; i++) X putchar(buf[i]); X printf("\n\\end{verbatim}\n"); X} X X Xvoid XscanTimeStamp() X{ X register int i; X X printf("\n\\markright{\\it "); X i = 1; X while (buf[i] != '\'') X putchar(buf[i++]); X printf("}"); X} X X Xvoid XscanComment() X{ X register int i, line_length; X X line_length = 0; X printf("{\\it "); X for (i = 0; buf[i] != '!'; line_length++,i++) X switch (buf[i]){ X case ' ': X if (line_length < 200) putchar(buf[i]); /* prevent long lines */ X else {putchar('\n'); line_length = 0;} X break; X case '#': X printf("\\#"); X break; X case '$': X printf("\\$"); X break; X case '&': X printf("\\&"); X break; X case '%': X printf("\\%"); X break; X case '{': X printf("\\{"); X break; X case '}': X printf("\\}"); X break; X case '<': X printf(" $<$ "); X break; X case '>': X printf(" $>$ "); X break; X default: X putchar(buf[i]); X break; X } X printf("}\n"); X} X X Xvoid XscanDefinition() X{ X char word[100]; X int wordIndex; X# define W_SUPERCLASS 1 X# define W_CLASS 3 X# define W_INSTVAR 5 X X extractWord(W_CLASS, word); X printf("\n\\markright{\\bf %s}\n", word); X printf("\\vskip 0.2in\n"); X printf("\\begin{center}\n{\\LARGE \\bf %s}\n\\end{center}\n", word); X printf("\\hskip 3in\n"); X X printf("\\begin{tabbing}\n"); X printf("instance variable names (set tabs out here) \\=\\kill\n"); X printf("class name\\> {\\bf %s}\\\\ \n", word); X X extractWord(W_SUPERCLASS, word); X printf("superclass\\> {\\bf %s}\\\\ \n", word); X X wordIndex = W_INSTVAR; X if (checkWord(W_INSTVAR, "classVariableNames:")) X printf("instance variable names\\> {\\it none}\\\\ \n"); X else { X extractWord(W_INSTVAR, word); X printf("instance variable names \\> {\\bf %s}\\\\ \n", word); X wordIndex++; X while (!checkWord(wordIndex, "classVariableNames:")) { X extractWord(wordIndex++, word); X printf("\\> {\\bf %s}\\\\ \n", word); X } X } X X wordIndex++; X if (checkWord(wordIndex, "poolDictionaries:")) X printf("class variable names\\> {\\it none}\\\\ \n"); X else { X extractWord(wordIndex++, word); X printf("class variable names\\> {\\bf %s}\\\\ \n", word); X while (!checkWord(wordIndex, "poolDictionaries:")) { X extractWord(wordIndex++, word); X printf("\\> {\\bf %s}\\\\ \n", word); X } X } X X wordIndex++; X if (checkWord(wordIndex, "category:")) X printf("pool dictionaries\\> {\\it none}\\\\ \n"); X else { X extractWord(wordIndex++, word); X printf("pool dictionaries\\> {\\bf %s}\\\\ \n", word); X while (!checkWord(wordIndex, "category:")) { X extractWord(wordIndex++, word); X printf("\\> {\\bf %s}\\\\ \n", word); X } X } X X extractWord(++wordIndex, word); X printf("category\\> {\\bf %s}\n", word); X X printf("\\end{tabbing}\n\n\n"); X /* set tabs here */ X} X X X/* X * returns the index of the first character in buf[] of the index'th X * word. X */ X Xint XbufIndex(index) Xint index; X{ X int i = 0; X X while (--index) { X while (!isspace(buf[i])) X i++; X while (isspace(buf[i]) || buf[i] == '\'' || buf[i] == '#') X i++; X } X return(i); X} X X X/* X * returns TRUE if index'th word in buf[] matches aString. X */ X Xboolean XcheckWord(index, aString) Xint index; Xchar aString[]; X{ X char word[100]; X X extractWord(index, word); X return(!strcmp(word, aString) ? TRUE : FALSE); X} X X X/* X * Extracts the index'th word from buf[] and stores it as a X * null terminated string in aString. X */ X Xvoid XextractWord(index, aString) Xint index; Xchar aString[]; X{ X int i, j; X X i = bufIndex(index); X j = 0; X while (!isspace(buf[i]) && buf[i] != '\'') X aString[j++] = buf[i++]; X aString[j] = '\0'; X} X X X/* X * Copies a method definition expression to the output. X * Some characters must be handled differently. X */ X Xvoid XscanMethod() X{ X register int i, column; X register boolean inComment = FALSE, inString = FALSE; X X i = 0; X while (isspace(buf[i])) X i++; X /* method start */ X printf("{\\bf\\noindent "); X while (buf[i] != '\n') X putchar(buf[i++]); X printf("}\n"); X X/* printf("\\begin{verse}\n"); */ X printf("\\begin{tabbing}\n"); X /* set tab stops */ X printf("eee \\= eee \\= eee \\= eee \\= eee \\= eee \\= eee \\= eee \\= eee \\= eee \\= eee \\= eee \\= eee \\= \\kill\n"); X column = 0; X while (buf[i] != '\0') { X switch (buf[i]) { X case '.': /* WHAT ARE WE DOING HERE ??? */ X if (i == 0 || buf[i-1] == '\n') X printf("%c",buf[i]); X else X putchar(buf[i]); X break; X case '\'': X if (i == 0 || buf[i - 1] == '\n') X printf("%c", buf[i]); X else X putchar(buf[i]); X if (!inComment) inString = !inString; X break; X case '\n': X if ((column != 0) && (buf[i-1] != '\n')) X printf(" \\quad\\\\{}\n"); X column = 0; X break; X case '\t': X if (!inComment) X printf(" \\> "); X else X printf(" \\> \\it "); X break; X case '^': X printf(" $\\uparrow$ "); X break; X case '_': X printf(" $\\leftarrow$ "); X break; X case '\\': X printf(" $\\backslash$ "); X break; X case '~': X printf(" $\\sim$ "); X break; X case '!': X if (buf[i + 1] == '!') { X putchar('!'); X i++; X } X break; X case '|': X printf(" $|$ "); X break; X case '"': X if (inString) { X printf("\'\'"); X break; X } X if (inComment) X printf("\'\'\n\\rm "); X else X printf("\\it ``"); X inComment = !inComment; X break; X case '#': X printf("\\#"); X break; X case '$': X printf("\\$"); X if (buf[i+1]== '"') { i++; printf("\'\'");} X else if (buf[i+1] == '\'') {i++; printf("\'");} X break; X case '&': X printf("\\&"); X break; X case '%': X printf("\\%"); X break; X case '{': X printf("\\{"); X break; X case '}': X printf("\\}"); X break; X case '<': X printf(" $<$ "); X break; X case '>': X printf(" $>$ "); X break; X default: X putchar(buf[i]); X break; X } X i++; X column++; X } X/* printf("\\end{verse}\n"); */ X printf("\\end{tabbing}\n\n\n"); X} X X X/* X * !<class> class methodsFor: 'class protocol name'! X * !<class> methodsFor: 'protocol name'! X */ X Xvoid XscanMethodsFor() X{ X register int i; X# define M_CLASS_KW 2 X# define M_PROTOCOL 3 X X if (checkWord(M_CLASS_KW, "class")) { X printf("\\vskip 0.2in\n"); X printf("{\\Large\\bf Class Protocols For: \n"); X i = bufIndex(M_PROTOCOL + 1); X while (buf[i] != '\'') X putchar(buf[i++]); X } X else { X printf("\\vskip 0.2in\n"); X printf("{\\Large\\bf Instance Protocols For: \n"); X i = bufIndex(M_PROTOCOL); X while(buf[i] != '\'') X putchar(buf[i++]); X } X printf("}\n\\vskip 0.1in\n"); X} X X X/* X * <class> comment: 'This class has no comment.'! X */ X Xvoid XscanClassComment() X{ X register int i, line_length; X# define COMMENT_START 3 X X printf("comment\n\\begin{quotation}\n{\\it "); X i = bufIndex(COMMENT_START); X for (line_length=0;;line_length++) { X if (buf[i] == '\'') { X if (buf[i + 1] == '\'') /* ... '' ... */ X putchar('\''); X else if (buf[i + 1] == '!') /* ... .'! */ X break; X else /* ... ' ... */ X putchar(buf[i]); X } X else if (buf[i] == '!') /* ... .! */ X break; X else if (buf[i] == '\\') X printf("\\"); X else if (buf[i] == '\t') { X if (i != 0 && buf[i - 1] == '\n') X printf("\n\t"); X else X putchar('\t'); X } X else if (buf[i] == '#') X printf("\\#"); X else if (buf[i] == ' ') { X if (line_length < 200) putchar(buf[i]); /* prevent long lines */ X else {putchar('\n'); line_length=0;} X } X else X putchar(buf[i]); X i++; X } X printf("}\n\\end{quotation}\n"); X} X X Xvoid Xgetargs(argc, argv) Xint argc; Xchar **argv; X{ X register char *ch; X X while (--argc > 0 && (*++argv)[0] == '-') X for (ch=argv[0]+1; *ch!='\0'; ch++) X switch (*ch) { X/* case 'm': X if (*(ch + 1) == '\0') { X strcpy(macros, *++argv); X --argc; X *ch = '\0'; X } X else { X strcpy(macros, ch + 1); X *(ch + 1) = '\0'; X } X break; X*/ X default: X fprintf(stderr, X "Usage: stLgrind file\n"); X exit(-1); X break; X } X X /* X * If there are any more arguments left, open that file and X * set input to its fp. X */ X X if (argc == 0) { X infp = stdin; X strcpy(filename, "stdin"); X } X else if (argc != 1) { X fprintf(stderr, "Usage: stLgrind file\n"); X exit(-1); X } X else if ((infp = fopen(*argv, "r")) == NULL) { X fprintf(stderr, "stLgrind: cannot open file: %s\n", *argv); X exit(1); X } X else X strcpy(filename, *argv); X} X X X/* X * Returns the date string X */ X Xchar * Xdate() X{ X long now; X char *string; X extern char *ctime(); X X now = time(0); X string = ctime(&now); X string[24] = '\0'; X return(string); X} SHAR_EOF if test 14342 -ne "`wc -c < 'stLgrind.c'`" then echo shar: error transmitting "'stLgrind.c'" '(should have been 14342 characters)' fi fi # end of overwriting check # End of shell archive exit 0 -- Herb Barad [USC - Signal and Image Processing Institute] USENET: ...!sdcrdcf!oberon!brand!barad or ...!mcvax!seismo!sdcsvax!sdcrdcf!oberon!brand!barad ARPANET: barad@brand.usc.edu