%{ #define LEX_STK_SIZE 256 int lex_stk[LEX_STK_SIZE]; int lex_stk_top = 0; #define PUSH(x) lex_stk[++lex_stk_top] = (x); BEGIN(x) #define POP BEGIN(lex_stk[--lex_stk_top]) #define LEX_STK_TOP lex_stk[lex_stk_top] #define LEX_NEXT_TO_STK_TOP lex_stk[lex_stk_top - 1] #define CHG_TOP(x) lex_stk[lex_stk_top] = (x); BEGIN(x) #define CHG_NEXT_TO_TOP(x) lex_stk[lex_stk_top - 1] = (x) /* not a lot in the old stack {over,under}flow dept, what? */ extern char *yytext; /* forward decl */ void print_leading_whitespace(); void print_lex_stk () /* just for debugging */ { int i; fprintf(stderr,"lex_stk:"); for (i = lex_stk_top; i >= 0; i--) { fprintf(stderr," %d",lex_stk[i]); } fprintf(stderr,"::%s\n",yytext); } int verbose; /* set from first argv */ int follow_inputs; /* set from second argv */ #if defined (SYSV) || defined (SYSV) #include #include #else #include #include #endif #if defined (SYSV) #define index(string, ch) strchr ((string), (ch)) #endif #define INPUTFILE_STK_SIZE 20 struct { YY_BUFFER_STATE handle; /* flex-supplied magic */ char* name; int lineno; } inputfile_stk[INPUTFILE_STK_SIZE]; int inputfile_stk_top = 0; void push_inputfile(); void pop_inputfile(); int i; /* temporary */ char* rbrace; int deatify_debug = 0; int unmatched_lbraces = 0; int unmatched_lbrackets = 0; /* like everything, must track srcfile name and lineno */ char srcfile_name[1024]; /* too lazy to do this right */ int lineno = 1; /* count \n's as they go by */ int lineno_fiddled = 0; /* boolean: incr if newlines get trashed */ int exit_status = 0; void not_OK (); /* prints an error msg and bumps exit_status */ void warning (); /* same, but no exit-status fiddling */ int lit2what; /* set from ARGV */ #define IS_LIT2PGM_Q (lit2what == 1) #define IS_LIT2PGM (lit2what == 2) #define IS_LIT2TEXI (lit2what == 3) #define IS_LIT2LATEX (lit2what == 4) #define IS_LIT2DEPEND (lit2what == 5) #define IS_LIT2CHANGELOG (lit2what== 6) /* the condition for printing to stdout */ #define SHLD_PRINT (! IS_LIT2PGM_Q || (LEX_STK_TOP == Code || LEX_STK_TOP == Bird)) void myecho(); #define MYECHO myecho() void myprintstr(); #define YY_USER_ACTION if (deatify_debug) print_lex_stk(); /* debugging */ %} D [0-9]+ END_WORD [-~/!\?(),\.'`A-Za-z0-9]*[ \t]* %x Norm Verb Code Bird Atting Math Index Typing Linify_braces Linify_brackets %% CHG_TOP(Norm); /* that's where we start */ [\001\002\003] { not_OK("ASCII chars \001, \002, \003 may not appear in literate files\n"); exit(1); } ^"srcfile!_!"(.+)"!_!"([0-9]+)"!_!"\n { sscanf(yytext+10,"%[^!]!_!%d", srcfile_name, &lineno); if (lineno > 0) { ECHO; } } ^\\input\{[^\}\n]+\}.*\n { lineno++; if (follow_inputs) { /* nullify first right brace */ rbrace = index(yytext+7,'}'); *rbrace = '\0'; push_inputfile(yytext+7); } else { MYECHO; } } <> { if ( inputfile_stk_top <= 0 ) { yyterminate(); } else { pop_inputfile(); } CHG_TOP(Norm); /* revert */ } ^\\begin\{verbatim\}.*\n | ^\\begin\{flushverbatim\}.*\n | ^\\begin\{pseudocode\}.*\n { lineno++; MYECHO; PUSH(Verb); /* some may have opt arg */ } ^\\begin\{code\}.*\n { lineno++; if (IS_LIT2PGM_Q) { printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); } MYECHO; PUSH(Code); } \n[ \t]+\n\> { /* convert to something less weird & try again */ unput('>'); unput('\n'); unput('\n'); } \n\n\>.*\n { lineno += 3; /* NB: init > converted to space */ if (IS_LIT2PGM_Q) { printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); printf("%s",yytext+3); } else { ECHO; } PUSH(Bird); } \n\>.*\n { lineno++; /* so msg will have right line # */ if (lineno > 2) /* I feel guilty about this hack */ /* to avoid: file is: blank lines, then code */ not_OK("Bird-style code not preceded by a blank line\n"); lineno++; /* account for other \n */ if (IS_LIT2PGM_Q) { printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); printf("%s",yytext+2); } else { ECHO; } PUSH(Bird); } ^\>.*\n { lineno++; /* first line of file */ if (IS_LIT2PGM_Q) { printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,(lineno-1)); printf("%s",yytext+1); } else { ECHO; } PUSH(Bird); } \\author\{ { MYECHO; PUSH(Linify_braces); } \\caption\{ { MYECHO; PUSH(Linify_braces); } \\centerline\{ { MYECHO; PUSH(Linify_braces); } \\date\{ { MYECHO; PUSH(Linify_braces); } \\define\{ { MYECHO; PUSH(Linify_braces); } \\heading\{ { MYECHO; PUSH(Linify_braces); } \\label\{ { MYECHO; PUSH(Linify_braces); } \\menuentry\{ { MYECHO; PUSH(Linify_braces); } \\node\{ { MYECHO; PUSH(Linify_braces); } \\owner\{ { MYECHO; PUSH(Linify_braces); } \\[sub]*section{D}?\{ { MYECHO; PUSH(Linify_braces); } \\[sub]*section{D}?\[ { MYECHO; PUSH(Linify_brackets); } \\standaloneornot\{ { MYECHO; PUSH(Linify_braces); } \\title\{ { MYECHO; PUSH(Linify_braces); } \\(tr|pl)\{ { MYECHO; unmatched_lbraces = 1; PUSH(Typing); /* \tr has braces as literals */ } \\item\[ { MYECHO; PUSH(Linify_brackets); } \\@ { MYECHO; } @ { myprintstr("\\codeInText{"); PUSH(Atting); } \\\$ { MYECHO; } \$ { myprintstr("\\MathMode{"); PUSH(Math); } \\index\{ { MYECHO; unmatched_lbraces = 1; PUSH(Index); } \\\{ { MYECHO; } \\\} { MYECHO; } \\% { MYECHO; } \%.*\n[ \t]*\n> { /* technically this Bird-style code is wrong (no blank line in front of it, but that's not intuitively obvious to the casual observer). Solution? A hack! */ unput('>'); unput('\n'); unput('\n'); } \%.*\n { /* throw away */ lineno++; if (! IS_LIT2PGM_Q) printf("\nsrcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); } [A-Za-z0-9 \t]+ { MYECHO; /* slight efficiency */ } . { MYECHO; } \n { /* handle line-number fiddling */ MYECHO; lineno++; if (lineno_fiddled) { if (! IS_LIT2PGM_Q) printf("srcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); lineno_fiddled = 0; } } ^\\end\{verbatim\} | ^\\end\{flushverbatim\} | ^\\end\{pseudocode\} { MYECHO; POP; } ^\\end\{code\} { if (! IS_LIT2PGM_Q) ECHO; POP; } ^[^\\\n].*\n { lineno++; MYECHO; /* a line not started by \ */} . { MYECHO; } \n { lineno++; MYECHO; } <> { not_OK("unexpected end-of-file in verbatim text or (pseudo)code\n"); exit(1); } [ \t\n]*\n\>.*\n? { /* whitespace/blank-lines do not matter */ /* count lines... */ for (i = 0; i < strlen(yytext); i++) { if (yytext[i] == '\n') lineno++; } if (! IS_LIT2PGM_Q) { ECHO; } else { /* don't print leading whitestuff */ for (i = 0; i < strlen(yytext) && yytext[i] != '>'; i++) ; /* no-op */ /* report where this got us...*/ printf("srcfile!_!%s!_!%d!_!\n",srcfile_name, ((yytext[yyleng-1] == '\n') ? (lineno-1) : lineno)); /* putchar(' '); convert leading > to space */ for ( i++ ; i < strlen(yytext); i++) putchar(yytext[i]); } } ^\>.*\n? { if (yytext[yyleng-1] == '\n') { lineno++; } if (IS_LIT2PGM_Q) printf("%s",yytext+1); else ECHO; } [ \t]*\n { lineno++; if ( ! IS_LIT2PGM_Q) ECHO; POP; } . { lineno--; /* to get right # on msg */ not_OK("Bird-style code not followed by a blank line\n"); lineno++; /* put it back */ unput(yytext[0]); POP; } @@ { myprintstr("@"); } @\\noindex\{\} | @\\noindex { myprintstr("\001noindex\003}"); POP; } @ { myprintstr("}"); POP; } \{ { myprintstr("\001lbrace\003"); } \} { myprintstr("\001rbrace\003"); } \n { warning("I'm turning a newline inside a @...@ into a space\n"); myprintstr(" "); lineno++; } <> { not_OK("unexpected end-of-file inside an @ ... @\n"); exit(1); } [A-Za-z0-9 \t]+ { MYECHO; /* tiny efficiency */ } . { MYECHO; } \\\$ { MYECHO; } \$ { myprintstr("}"); POP; } \{ { myprintstr("\001lbrace\003"); } \} { myprintstr("\001rbrace\003"); } \n { myprintstr("\001newline\003"); lineno++; } <> { not_OK("unexpected end-of-file inside $ ... $ (math mode)\n"); exit(1); } [A-Za-z0-9 \t]+ { MYECHO; /* tiny efficiency */ } . { MYECHO; } \\(tr|pl)\{ { MYECHO; unmatched_lbraces = 1; PUSH(Typing); } \\\\ { MYECHO; } \\ { MYECHO; } \\\{ { MYECHO; } \{ { MYECHO; PUSH(Linify_braces); } \{ { MYECHO; } \{ { unmatched_lbraces++; myprintstr("\001lbrace\003"); } \\\} { MYECHO; } \}\{ { /* next arg */ MYECHO; } \} { MYECHO; POP; } \} { MYECHO; } \} { if (--unmatched_lbraces == 0) { MYECHO; POP; } else { myprintstr("\001rbrace\003"); } } \\@ { MYECHO; } @ { myprintstr("\\codeInText{"); /* no newline */ PUSH(Atting); } @ { MYECHO; /* NB: magic chars below */ } \\\$ { MYECHO; } \$ { myprintstr("\\MathMode{"); /* no newline */ PUSH(Math); } \$ { MYECHO; } \\% { MYECHO; } \%.*\n[ \t]*\n> { /* see earlier comments about crimes against humanity */ unput('>'); unput('\n'); unput('\n'); } \%.*\n { /* throw away */ lineno++; lineno_fiddled++; } % { MYECHO; } \\\[ { MYECHO; } \[ { MYECHO; PUSH(Linify_brackets); } \\\] { myprintstr("\\\001rbracket\003"); /* cannot have these in the way */ } \]\{ { if (LEX_NEXT_TO_STK_TOP == Norm) { MYECHO; } else { myprintstr("\001rbracket\003\{"); not_OK("WHAT'S GOING ON? ]{\n"); print_lex_stk(); } CHG_TOP(Linify_braces); } \] { if (LEX_NEXT_TO_STK_TOP == Norm) { MYECHO; } else { myprintstr("\001rbracket\003"); } POP; } \\\@ { MYECHO; /* my pseudo-makeindex has two magic chars */ } \@ { myprintstr("\001idxsort\003"); } \\! { MYECHO; } \! { myprintstr("\001idxsubitem\003"); } \n { lineno++; lineno_fiddled++; if (LEX_STK_TOP == Index) { warning("I'm turning a newline inside an \\index{...} into a space\n"); myprintstr(" "); } else if (LEX_STK_TOP == Typing) { warning("I'm turning a newline inside a \\tr{...} or \\pl{...} into a space\n"); myprintstr(" "); } else { myprintstr("\001newline\003"); } } [A-Za-z0-9 \t]+ { MYECHO; /* tiny efficiency */ } . { MYECHO; /* catch all */ } <> { not_OK("unexpected end-of-file inside an \\index{...}\n"); exit(1); } <> { not_OK("unexpected end-of-file inside a macro argument\n"); exit(1); } <> {not_OK("unexpected end-of-file inside a macro optional argument\n"); exit(1); } <> { not_OK("unexpected end-of-file inside a \\tr{...}\n"); exit(1); } %% main(argc, argv) int argc; char **argv; { if (argc != 5) { fprintf(stderr,"Sorry, %s must have exactly 4 arguments\n", argv[0]); exit(1); } verbose = argv[1][0] - '0'; /* hacks */ follow_inputs = argv[2][0] - '0'; lit2what = argv[3][0] - '0'; /* used in IS_LIT2xxx tests */ if (strcmp(argv[4], "-") == 0) { yyin = stdin; } else if ((yyin = fopen(argv[4], "r")) == NULL) { fprintf(stderr,"%s: can't open file %s\n", argv[0], argv[4]); exit(1); } strcpy(srcfile_name, argv[4]); inputfile_stk[ inputfile_stk_top /* 0 */ ].name = argv[4]; if ( ! IS_LIT2PGM_Q ) printf("srcfile!_!%s!_!1!_!\n",argv[4]); yylex(); exit(exit_status); } void push_inputfile (fname) char* fname; { if ( inputfile_stk_top >= INPUTFILE_STK_SIZE ) { fprintf(stderr,"\\input's too deeply nested\n"); exit(1); } /* record where we are in current file */ inputfile_stk[ inputfile_stk_top ].lineno = lineno; inputfile_stk[ inputfile_stk_top ].handle = YY_CURRENT_BUFFER; /* actual push */ inputfile_stk_top++; /* open new file fname */ if ((yyin = fopen(fname, "r")) == NULL) { fprintf(stderr,"%s:%d: can't open \\input file %s\n", srcfile_name, lineno, fname); exit(1); } yy_switch_to_buffer( yy_create_buffer( yyin, YY_BUF_SIZE ) ); /* report that's where we are */ if (! IS_LIT2PGM_Q) printf("srcfile!_!%s!_!1!_!\n",fname); /* set srcfile_name and lineno for new file */ strcpy(srcfile_name, fname); /* for my own tracking */ lineno = 1; /* push/record everything for new file */ inputfile_stk[ inputfile_stk_top ].name = srcfile_name; inputfile_stk[ inputfile_stk_top ].lineno = lineno; } void pop_inputfile () { inputfile_stk_top--; /* actual pop */ /* remind where we were */ strcpy(srcfile_name, inputfile_stk[inputfile_stk_top].name); lineno = inputfile_stk[inputfile_stk_top].lineno; /* put in an extra newline or two before the next file; otherwise, the cat'ting of files gives things like: > last line of code \section{Next section} which happens to be very bad for lit2stuff. */ if (! IS_LIT2PGM_Q) printf("\n\nsrcfile!_!%s!_!%d!_!\n",srcfile_name,lineno); /* return to prev inputfile */ yy_switch_to_buffer( inputfile_stk[inputfile_stk_top].handle ); } void myecho () { myprintstr(yytext); } void myprintstr (str) char *str; { if (SHLD_PRINT) { printf("%s",str); } } void print_leading_whitespace () { int i; for (i = 0; yytext[i] == ' ' || yytext[i] == '\t'; i++) { putchar(yytext[i]); } } void not_OK(msg) char *msg; { /* a good old emacsable error msg */ fprintf(stderr,"%s:%d: %s", srcfile_name, lineno, msg); exit_status++; } void warning(msg) /* exit_status not fiddled */ char *msg; { /* a good old emacsable warning msg */ fprintf(stderr,"%s:%d: [warning] %s", srcfile_name, lineno, msg); }