home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume26
/
schemeweb
/
part01
/
sweb.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-27
|
8KB
|
323 lines
/* SchemeWEB -- WEB for Scheme. John D. Ramsdell.
* Simple support for literate programming in Scheme.
* This file generates both a Scheme weave program and
* a Scheme tangle program depending on if TANGLE is defined.
*/
#if !defined lint
static char ID[] = "$Header: sweb.c,v 1.2 90/07/17 07:25:01 ramsdell Exp $";
static char copyright[] = "Copyright 1990 by The MITRE Corporation.";
#endif
/*
* Copyright 1990 by The MITRE Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a copy of the GNU General Public License, write to the
* Free Software Foundation, Inc., 675 Mass Ave,
* Cambridge, MA 02139, USA.
*/
/* SchemeWEB defines a new source file format in which source lines
are divided into text and code. Lines of code start with a line
beginning with '(', and continue until the line that contains the
matching ')'. The text lines remain, and they are treated as
comments. If the first character of a text line is ';', it is
stripped from the output. This is provided for those who want to use
an unmodified version of their Scheme system's LOAD. When producing a
document, both the text lines and the code lines are copied into the
document source file, but the code lines are surrounded by a pair of
formatting commands, as is comments beginning with ';' within code
lines. SchemeWEB is currently set up for use with LaTeX. */
/* Define TANGLE to make a program which translates SchemeWEB source
into Scheme source. */
/* Define SAVE_LEADING_SEMICOLON if you want text lines to be copied
with any leading semicolon. */
#include <stdio.h>
typedef enum {FALSE, TRUE} bool;
#define putstring(s) (fputs(s, stdout))
#if defined TANGLE
#define sweb_putchar(c) (putchar(c))
#else
/* Modify the following for use with something other than LaTeX. */
#define BEGIN_COMMENT "\\notastyped{"
#define BEGIN_CODE "\\begin{astyped}"
#define END_CODE "\\end{astyped}"
void sweb_putchar (c)
int c;
{ /* Raps \verb around characters */
switch (c) { /* which LaTeX handles specially. */
case '\\':
case '{':
case '}':
case '$':
case '&':
case '#':
case '^':
case '_':
case '%':
case '~':
putstring("\\verb-");
putchar(c);
putchar('-');
break;
default: putchar(c);
}
}
#endif
/* Error message for end of file found in code. */
bool report_eof_in_code()
{
fprintf(stderr, "End of file within a code section.\n");
return TRUE;
}
/* All input occurs in the following routines so that TAB characters
can be expanded. TeX treats TAB characters as a space--not what is
wanted. */
int ch_buf;
bool buf_used = FALSE;
int lineno = 1;
#undef getchar()
int getchar()
{
int c;
static int spaces = 0; /* Spaces left to print a TAB. */
static int column = 0; /* Current input column. */
if (buf_used) {
buf_used = FALSE;
return ch_buf;
}
if (spaces > 0) {
spaces--;
return ' ';
}
switch (c = getc(stdin)) {
case '\t':
spaces = 7 - (7&column); /* Maybe this should be 7&(~column). */
column += spaces + 1;
return ' ';
case '\n':
lineno++;
column = 0;
return c;
default:
column++;
return c;
}
}
void ungetchar(c)
int c;
{
buf_used = TRUE;
ch_buf = c;
}
bool copy_text_saw_eof()
{
int c;
while (1) {
c = getchar();
if (c == EOF) return TRUE;
if (c == '\n') return FALSE;
#if !defined TANGLE
putchar(c);
#endif
}
}
bool copy_comment_saw_eof() /* This copies comments */
{ /* within code sections. */
#if !defined TANGLE
putstring(BEGIN_COMMENT);
putchar(';');
#endif
if (copy_text_saw_eof()) return TRUE;
#if !defined TANGLE
putchar('}');
#endif
putchar('\n');
return FALSE;
}
bool after_sexpr_failed() /* Copies comments in a code */
{ /* section that follow a */
int c; /* complete S-expr. */
while (1) /* It fails when there is */
switch (c = getchar()) { /* something other than */
case EOF: /* white space or a comment, */
return report_eof_in_code(); /* such as an extra ')'. */
case ';':
#if !defined TANGLE
putstring(BEGIN_COMMENT);
putchar(c);
#endif
if (copy_text_saw_eof()) return report_eof_in_code();
#if !defined TANGLE
putchar('}');
#endif
putchar('\n');
return FALSE;
case '\n':
putchar(c);
return FALSE;
case ' ':
#if !defined TANGLE
putchar(c);
#endif
break;
default:
fprintf(stderr,
"Found \"%c\" after an S-expr finished.\n",
c);
return TRUE;
}
}
bool copy_string_saw_eof()
{
int c;
while (1) {
c = getchar();
if (c == EOF) return TRUE;
sweb_putchar(c);
switch (c) {
case '"': return FALSE;
case '\\':
c = getchar();
if (c == EOF) return TRUE;
sweb_putchar(c);
}
}
}
bool maybe_char_syntax_saw_eof()
{ /* Makes sure that the character */
int c; /* #\( does not get counted in */
c = getchar(); /* balancing parentheses. */
if (c == EOF) return TRUE;
if (c != '\\') {
ungetchar(c);
return FALSE;
}
sweb_putchar(c);
c = getchar();
if (c == EOF) return TRUE;
sweb_putchar(c);
return FALSE;
}
bool copy_code_failed() /* Copies a code section */
{ /* containing one S-expr. */
int parens = 1; /* Used to balance parentheses. */
int c;
while (1) { /* While parens are not balanced, */
c = getchar();
if (c == EOF) /* report failure on EOF and */
return report_eof_in_code();
if (c == ';') /* report failure on EOF in a comment. */
if (copy_comment_saw_eof()) return report_eof_in_code();
else continue;
sweb_putchar(c); /* Write the character and then see */
switch (c) { /* if it requires special handling. */
case '(':
parens++;
break;
case ')':
parens--;
if (parens == 0) /* Parentheses balance! */
return after_sexpr_failed(); /* Report the result of */
break; /* post S-expr processing. */
case '"': /* Report failure on EOF in a string. */
if (copy_string_saw_eof()) {
fprintf(stderr, "End of file found within a string.\n");
return TRUE;
}
break;
case '#': /* Report failure on EOF in a character. */
if (maybe_char_syntax_saw_eof()) return report_eof_in_code();
break;
}
}
}
int filter()
{
int c;
while (1) { /* At loop start it's in text mode */
c = getchar(); /* and at the begining of a line. */
if (c == '(') { /* text mode changed to code mode. */
#if !defined TANGLE
putstring(BEGIN_CODE); putchar('\n');
#endif
do { /* Copy code. */
putchar(c);
if (copy_code_failed()) {
fprintf(stderr,
"Error in the code section containing line %d.\n",
lineno);
return 1;
}
c = getchar(); /* Repeat when there is code */
} while (c == '('); /* immediately after some code. */
#if !defined TANGLE
fputs(END_CODE, stdout); putc('\n', stdout);
#endif
}
/* Found a text line--now in text mode. */
#if !defined SAVE_LEADING_SEMICOLON
if (c == ';') c = getchar();
#endif
ungetchar(c);
if (copy_text_saw_eof()) return 0; /* Copy a text line. */
#if !defined TANGLE
putchar('\n');
#endif
}
}
int main (argc, argv) /* For machines which do not */
int argc; /* support argc and argv, */
char *argv[]; /* just change main. */
{
switch (argc) {
case 3:
if (NULL == freopen(argv[2], "w", stdout)) {
fprintf(stderr, "Cannot open %s for writing.\n", argv[2]);
break;
}
case 2:
if (NULL == freopen(argv[1], "r", stdin)) {
fprintf(stderr, "Cannot open %s for reading.\n", argv[1]);
break;
}
case 1:
return filter();
}
fprintf(stderr,
#if defined TANGLE
"Usage: %s [SchemeWEB file] [Scheme file]\n",
#else
"Usage: %s [SchemeWEB file] [LaTeX file]\n",
#endif
argv[0]);
return 1;
}