%{
/*
* l2x.l     --- (flex) lexer for converting a LaTeX file to X
*           Written by Peter Wilson (Catholic University and NIST)
*           Version 0.2, January 1995
*           Revised July 1996
*           -- replace myprint(tag) by tag_print(tag)
*           -- added verb(atim) like capability
*/

/* Development of this software was funded by the United States Government,
* and is not subject to copyright.
*/

#include <string.h>
#ifndef STRTYPES_H
#include "strtypes.h"
#endif
#ifndef L2XCOM_H
#include "l2xcom.h"
#endif
#include "l2xytab.h"     /* token codes from parser */
#include "l2xlib.h"      /* functions and global variables */
#include "l2xusrlb.h"    /* possibly useful strings and user-defined functions */


extern int opt_param;
extern int all_opt;
extern int opt_coord;
int got_opt_item = FALSE;
int got_a_dollar = FALSE;
int got_opt_param = FALSE;
int got_all_opt = FALSE;
int got_opt_coord = FALSE;


char verb_char;         /* delimeter for \verb command */
int result;
int kind;
int special_kind;
PSENTRY ptr;            /* pointer to sym entry */
int nl_count = 0;       /* number of consecutive new lines */
char a_newline[] = "\n";
char a_space[] = " ";
char vlenv[80];         /* name of verbatim-like environment */
int nopen_vbrace = 0;   /* no of unmatched open braces after verb-like command */

int nopen_noop = 0;     /* no of unmatched openers for no_op argument */
#define NOOPLBRAK 1
#define NOOPRBRAK 1
#define NOOPLBRACE 2
#define NOOPRBRACE 2
int noop_openc;        /* noop argument opening character ( [ or { )*/

#define LDA -1
#define LD0 0
#define LD1 1
#define LD2 2
#define LD3 3
#define LD4 4
#define LD5 5
#define LD6 6
/*
* LDEBUG > LDA: error prints:
*        > LD0:               names not in command table
*        > LD1:               newlines, returned useful tokens
*        > LD2:               general tokens
*        > LD3:               text dealt with in lexer
*        > LD4:               comments
*        > LD5:               stuff within verbatims
*        > LD6:
*
*/

%}

                                    /* whitespace and comments */
ws ([ \t])
newline (\n)
                    /* TeX comments from % through eol + any following whitespace */
tex_comment (%.*\n[ \t]*)
                                    /* general REs */
lbrace (\{)
rbrace (\})
lbrak (\[)
rbrak (\])
lparen (\()
rparen (\))
backslash (\\)
comma (",")
name ([a-zA-Z]+\*?)
integer (-?[0-9]+)
real (-?(([0-9]*\.[0-9]+)|([0-9]+\.[0-9]*)))
hash (#)
dollar ($)
ampersand (&)
twiddle (~)
underscore (_)
caret (^)
percent (%)
at (@)
slashspace (\\ )
                                      /* (La)TeX literals */
                                      /* general LaTeX commands */

verbatim (verbatim\*?)
command (\\[a-zA-Z]+\*?)
char_command (\\[^a-zA-Z\n])
begin_c (\\begin[ \t]*)
end_c (\\end[ \t]*)
verb (\\verb\*?)
                                          /* list items */
item (\\item[ \t]*)



%x VERBATIM_STATE
%x VERB_STATE
%x VERBATIM_LIKE
%x VERB_LIKE
%x NOOP
%%

     /*------------ Comments plus start and end document ---------------*/

{tex_comment} {
                if (LDEBUG > LD4) {
                  print_debug_2s("(tex_comment):", yytext);
                }
                catl(yyleng, yytext);
                do_newline();
                if (leave_comments) {  /* leave in comments */
                  myprint(yytext);
                }
              }


                /* \begin{document} */
{begin_c}{lbrace}{ws}*document{ws}*{rbrace} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(t_BEGIN_DOCUMENT):", yytext);
                 }
                 yylval.pos = get_mode_sym(pos_bdoc);
                 return(BEGIN_DOCUMENT);
               }

               /* end of document \end{document} */
{end_c}{lbrace}{ws}*document{ws}*{rbrace} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(t_END_DOCUMENT):", yytext);
                 }
                 yylval.pos = get_mode_sym(pos_edoc);
                 return(END_DOCUMENT);
               }




 /*----------------- verbatims -----------------------------------------*/
 /* Do most of the processing in the lexer */
 /* but pass token back to parser anyway */

                /* \begin{verbatim} */
{begin_c}{lbrace}{ws}*{verbatim}{ws}*{rbrace} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(begin{verbatim}):", yytext);
                 }
                 BEGIN VERBATIM_STATE;
                 yylval.pos = get_mode_sym(pos_bvbm);
                 bverb = TRUE;
                 return(BEGIN_VERBATIM);
               }
               /* newline */
<VERBATIM_STATE>{newline} { catl(yyleng, yytext);
                 do_newline();
                 if (LDEBUG > LD3) {
                   print_debug_2s("(newline in verbatim):", yytext);
                 }
                 verbatim_print(yytext);
               }
                /* backslash */
<VERBATIM_STATE>{backslash} { catl(yyleng, yytext);
                 if (LDEBUG > LD5) {
                   print_to_err(yytext);
                 }
                 verbatim_print(yytext);
               }
               /* any characters other than newline and backslash */
<VERBATIM_STATE>[^\n\\]+ { catl(yyleng, yytext);
                 if (LDEBUG > LD5) {
                   print_to_err(yytext);
                 }
                 verbatim_print(yytext);
               }
               /* \end{verbatim} */
<VERBATIM_STATE>{end_c}{lbrace}{ws}*{verbatim}{ws}*{rbrace} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(end{verbatim}):", yytext);
                 }
                 BEGIN 0;
                 yylval.pos = get_mode_sym(pos_evbm);
                 return(END_VERBATIM);
               }

                   /* \verb (and its trailing character) */
{verb}. { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(verb):", yytext);
                 }
                 BEGIN VERB_STATE;
                 verb_char = yytext[yyleng-1];
                 yylval.pos = get_mode_sym(pos_bv);
                 return(BEGIN_VERB);
               }

                  /* chars inside \verb */
<VERB_STATE>.   { catl(yyleng, yytext);
                 if (LDEBUG > LD5) {
                   print_to_err(yytext);
                 }
                 if (verb_char != yytext[0] ) {
                   myprint(yytext);
                 }
                 else {                 /* end of verb environment */
                   BEGIN 0;
                   yylval.pos = get_mode_sym(pos_ev);
                   return(END_VERB);
                 }
               }

                  /* newlines not allowed within verb */
<VERB_STATE>{newline}    { catl(yyleng, yytext);
                 nl_count++;
                 if (LDEBUG > LD5) {
                   print_to_err(yytext);
                 }
                 BEGIN 0;
                 yyerror("Error: \"verb\" ended by a newline");
                 do_newline();
                 myprint(a_newline);
                 yylval.pos = get_mode_sym(pos_ev);
                 return(END_VERB);
               }

               /* VERB LIKE command stuff */
                  /* { (open brace) */
<VERB_LIKE>{lbrace} { catl(yyleng, yytext);
                     nopen_vbrace++;
                     if (LDEBUG > LD5) {
                       print_to_err(yytext);
                     }
                     if (nopen_vbrace == 1) {    /* start of argument */
                       yylval.pos = get_mode_sym(pos_lbrace);
                       return(LBRACE);
                     }
                     else {                      /* part of argument */
                       verbatim_print(yytext);
                     }
                   }

                 /* } (close brace) */
<VERB_LIKE>{rbrace} { catl(yyleng, yytext);
                     nopen_vbrace--;
                     if (LDEBUG > LD5) {
                       print_to_err(yytext);
                     }
                     if (nopen_vbrace == 0) {    /* end of argument */
                       BEGIN 0;                  /* change state */
                       yylval.pos = get_mode_sym(pos_rbrace);
                       return(RBRACE);
                     }
                     else {                      /* part of argument */
                       verbatim_print(yytext);
                     }
                   }

                /* newline  */
<VERB_LIKE>{newline} { catl(yyleng, yytext);
                      do_newline();
                      if (LDEBUG > LD3) {
                        print_debug_2s("(newline in verb-like):", yytext);
                      }
                      verbatim_print(yytext);
                    }

                /* any other character */
<VERB_LIKE>.        { catl(yyleng, yytext);
                     if (LDEBUG > LD5) {
                       print_to_err(yytext);
                     }
                     verbatim_print(yytext);
                   }


                /* VERBATIM LIKE environment stuff */

                   /* \end{something} */
<VERBATIM_LIKE>{end_c}{lbrace}{ws}*{name}{ws}*{rbrace} { catl (yyleng, yytext);
                     nl_count = 0;
                     get_env_name(yytext);
                     if (strcmp(vlenv, env_name) == 0) { /* close verbatim like */
                       if (LDEBUG > LD1) {
                         print_debug_2s("(end):", yytext);
                         print_debug_2s("env_name= ", env_name);
                       }
                       result = lookup_entry(env_name, END_VENV);
                       if (result > 0) { /* found it */
                         ptr = get_mode_sym(result);
                         yylval.pos = ptr;
                         kind = command_type(ptr);
                         BEGIN 0;
                         return(kind);
                       }
                       else {           /* got problems, end env name not in table */
  warning_3s("END_VENV",env_name,"not in command table. Expect input/output errors from now on");
                         BEGIN 0;
                         verbatim_print(yytext);
                       }
                     }
                     else {      /* not end of verbatim-like env */
                       verbatim_print(yytext);
                     }
                   }

               /* newline */
<VERBATIM_LIKE>{newline} { catl(yyleng, yytext);
                 do_newline();
                 if (LDEBUG > LD3) {
                   print_debug_2s("(newline in verbatim-like):", yytext);
                 }
                 verbatim_print(yytext);
               }

                /* any other character */
<VERBATIM_LIKE>.      { catl(yyleng, yytext);
                       if (LDEBUG > LD5) {
                         print_to_err(yytext);
                       }
                       verbatim_print(yytext);
                     }

 /*---------------------------No Op processing---------------------------*/

                 /* open brace */
<NOOP>{lbrace} { catl(yyleng, yytext);
                  if (LDEBUG > LD5) {
                    print_to_err(yytext);
                  }
                  if (noop_openc == NOOPLBRACE) {
                    nopen_noop++;
                  }
               }

                 /* open bracket */
<NOOP>{lbrak} { catl(yyleng, yytext);
                  if (LDEBUG > LD5) {
                    print_to_err(yytext);
                  }
                  if (noop_openc == NOOPLBRAK) {
                    nopen_noop++;
                  }
               }

                 /* close brace */
<NOOP>{rbrace} { catl(yyleng, yytext);
                  if (LDEBUG > LD5) {
                    print_to_err(yytext);
                  }
                  if (noop_openc == NOOPLBRACE) {
                    nopen_noop--;
                    if (nopen_noop <= 0) {
                      if (LDEBUG > LD3) {
                        print_to_err("(Closing NO_OP on brace)");
                      }
                      nopen_noop = 0;
                      in_noop = FALSE;
                      start_noop = FALSE;
                      BEGIN 0;
                      yylval.pos = get_mode_sym(pos_rbrace);
                      return(RBRACE);
                    }
                  }
               }

                 /* close bracket */
<NOOP>{rbrak} { catl(yyleng, yytext);
                  if (LDEBUG > LD5) {
                    print_to_err(yytext);
                  }
                  if (noop_openc == NOOPLBRAK) {
                    nopen_noop--;
                    if (nopen_noop <= 0) {
                      if (LDEBUG > LD3) {
                        print_to_err("(Closing NO_OP on bracket)");
                      }
                      nopen_noop = 0;
                      in_noop = FALSE;
                      start_noop = FALSE;
                      BEGIN 0;
                      got_opt_param = FALSE;
                      return(END_ANOPT);
                    }
                  }
               }


               /* newline */
<NOOP>{newline} { catl(yyleng, yytext);
                 do_newline();
                 if (LDEBUG > LD3) {
                   print_debug_2s("(newline in a no op):", yytext);
                 }
               }

                /* any other character */
<NOOP>.      { catl(yyleng, yytext);
                       if (LDEBUG > LD5) {
                         print_to_err(yytext);
                       }
                     }

 /*----------------------------Default processing------------------------*/

         /*----------------------- list items ---------------------------*/

                /* item */
{item} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(t_ITEM):", yytext);
                 }
                 return(ITEM);
               }

                    /* item[ */
{item}{lbrak} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(t_ITEM_AND_BRAK):", yytext);
                 }
                 got_opt_item = TRUE;
                 return(ITEM_AND_BRAK);
               }


 /*------------------------------ commands ------------------------------*/

               /* (La)TeX backslash followed by a single space */
{backslash}[ ] { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD4) {
                   print_debug_2s("(slashspace):", yytext);
                 }  /* 6/96 change myprint to tag_print */
                 ptr = get_mode_sym(pos_bss);
                 tag_print(get_t(ptr));
                 tag_print(get_et(ptr));
               }

               /* (La)TeX backslash followed by a newline */
{backslash}[\n] { catl(yyleng, yytext);
                 nl_count++;
                 yylval.string = strsave(yytext);
                 do_newline();
                 if (LDEBUG > LD1) {
                   fprintf(filerr, "\n LD(slashnewline): next line is %d\n", lineno);
                   fflush(filerr);
                 }
                 ptr = get_mode_sym(pos_bss);
                 tag_print(get_t(ptr));
                 tag_print(get_et(ptr));
                 if (!pretty_print) {
                   myprint(a_newline);
                 }
               }

                /* \one non-alphabetic character */
{char_command} {catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(char_command):", yytext);
                 }
                 result = lookup_entry(yytext, CHAR_COMMAND);
                 if (result >= 0) {         /* found it */
                   ptr = get_mode_sym(result);
                   kind = command_type(ptr);
                   yylval.pos = ptr;
                   return(kind);
                 }
                 else {
                   yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER_COMMAND)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as CHAR_COMMAND)");
                   }
                   return(OTHER_COMMAND);
                }
              }

                  /* special processing for \\* command */
{backslash}{backslash}[ \t]*\* { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(char_command):", yytext);
                 }
                 result = lookup_entry("\\\\", CHAR_COMMAND);
                 if (result >= 0) {         /* found it */
                   ptr = get_mode_sym(result);
                   kind = command_type(ptr);
                   yylval.pos = ptr;
                   return(kind);
                 }
                 else {
                   yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER_COMMAND)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as CHAR_COMMAND)");
                   }
                   return(OTHER_COMMAND);
                }
              }



                 /* a command \something or \something* */
{command} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(command):", yytext);
                 }
                 result = lookup_entry(yytext, DONT_CARE);
                 if (result >= 0) {         /* found it */
                   ptr = get_mode_sym(result);
                   kind = command_type(ptr);
                   yylval.pos = ptr;
                   switch (get_user_type(ptr)) {
                     case SPECIAL_COMMAND: {
                       special_kind = get_special_token(ptr);
                       if (special_kind == COMMAND) {
                         warning_3s("SPECIAL_COMMAND",yytext,"not yet implemented");
                       }
                       if (special_kind >= MIN_CODE_SPECIAL) {
                         return(kind);
                       }
                       else {
                         return(special_kind);
                       }
                       break;
                     }
                     case SPECIAL_SECTIONING: {
                       special_kind = get_special_token(ptr);
                       if (special_kind == COMMAND) {
                         warning_3s("SPECIAL_SECTIONING",yytext,"not yet implemented");
                       }
                       if (special_kind >= MIN_CODE_SPECIAL) {
                         return(kind);
                       }
                       else {
                         return(special_kind);
                       }
                       break;
                     }
                     case VCOMMAND: {               /* verb-like */
                       BEGIN VERB_LIKE;
                       nopen_vbrace = 0;
                       break;
                     }
                   }  /* end switch */
                   return(kind);
                 }
                 else {
                   yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER_COMMAND)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as a command type)");
                   }
                   return(OTHER_COMMAND);
                 }
              }


   /*-------------------- Environments ---------------------------*/

                 /* \begin{something} */
{begin_c}{lbrace}{ws}*{name}{ws}*{rbrace} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(begin):", yytext);
                 }
                 get_env_name(yytext);
                 if (LDEBUG > LD1) {
                   print_debug_2s("env_name= ", env_name);
                 }
                 result = lookup_entry(env_name, BEGIN_ENV);
                 if (result >= 0) {             /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 result = lookup_entry(env_name, BEGIN_LIST_ENV);
                 if (result >= 0) {             /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 result = lookup_entry(env_name, BEGIN_PICTURE_CC);
                 if (result >= 0) {             /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 result = lookup_entry(env_name, BEGIN_VENV);
                 if (result >= 0) {          /* found it */
                   BEGIN VERBATIM_LIKE;      /* switch into verbatim-like mode */
                   bverb = TRUE;
                   strcpy(vlenv, env_name);     /* remember environment name */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 result = lookup_entry(env_name, SPECIAL_BEGIN_ENV);
                 if (result >= 0) {             /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   special_kind = get_special_token(ptr);
                   if (special_kind == COMMAND) {
                     warning_3s("SPECIAL_BEGIN_ENV",env_name,"not yet implemented");
                   }
                   if (special_kind >= MIN_CODE_SPECIAL) {
                     return(command_type(ptr));
                   }
                   else {
                     return(special_kind);
                   }
                 }
                 result = lookup_entry(env_name, SPECIAL_BEGIN_LIST);
                 if (result >= 0) {             /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   special_kind = get_special_token(ptr);
                   if (special_kind == COMMAND) {
                     warning_3s("SPECIAL_BEGIN_LIST",env_name,"not yet implemented");
                   }
                   if (special_kind >= MIN_CODE_SPECIAL) {
                     return(command_type(ptr));
                   }
                   else {
                     return(special_kind);
                   }
                 }
                 yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER_BEGIN)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as begin something)");
                   }
                 return(OTHER_BEGIN);
               }

                 /* \end{something} */
{end_c}{lbrace}{ws}*{name}{ws}*{rbrace} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(end):", yytext);
                 }
                 get_env_name(yytext);
                 if (LDEBUG > LD1) {
                   print_debug_2s("env_name= ", env_name);
                 }
                 result = lookup_entry(env_name, END_ENV);
                 if (result >= 0) {             /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 result = lookup_entry(env_name, END_LIST_ENV);
                 if (result >= 0) {             /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 result = lookup_entry(env_name, END_PICTURE);
                 if (result >= 0) {             /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 result = lookup_entry(env_name, SPECIAL_END_ENV);
                 if (result >= 0) {             /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   special_kind = get_special_token(ptr);
                   if (special_kind == COMMAND) {
                     warning_3s("SPECIAL_END_ENV",env_name,"not yet implemented");
                   }
                   if (special_kind >= MIN_CODE_SPECIAL) {
                     return(command_type(ptr));
                   }
                   else {
                     return(special_kind);
                   }
                 }
                 result = lookup_entry(env_name, SPECIAL_END_LIST);
                 if (result >= 0) {             /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   special_kind = get_special_token(ptr);
                   if (special_kind == COMMAND) {
                     warning_3s("SPECIAL_END_ENV",env_name,"not yet implemented");
                   }
                   if (special_kind >= MIN_CODE_SPECIAL) {
                     return(command_type(ptr));
                   }
                   else {
                     return(special_kind);
                   }
                 }
                 yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER_END)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as end something)");
                   }
                 return(OTHER_END);
               }


         /*--------------------- Miscellaneous stuff -----------------------*/


               /* an open brace { */
{lbrace}    { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(t_LBRACE):", yytext);
                 }
                 if (start_noop) {
                      if (LDEBUG > LD3) {
                        print_to_err("(Starting NO_OP on brace)");
                      }
                   start_noop = FALSE;
                   in_noop = TRUE;
                   nopen_noop = 1;
                   noop_openc = NOOPLBRACE;
                   BEGIN NOOP;
                 }
                 yylval.pos = get_mode_sym(pos_lbrace);
                 return(LBRACE);
               }

               /* a close brace } */
{rbrace}   { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(t_RBRACE):", yytext);
                 }
                 yylval.pos = get_mode_sym(pos_rbrace);
                 return(RBRACE);
               }

               /* an open bracket [ */
{lbrak}     { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(t_LBRAK):", yytext);
                 }
                 if (opt_param) {
                   got_opt_param = TRUE;
                   opt_param = FALSE;
                   if (start_noop) {
                      if (LDEBUG > LD3) {
                        print_to_err("(Starting NO_OP on bracket)");
                      }
                     start_noop = FALSE;
                     in_noop = TRUE;
                     noop_openc = NOOPLBRAK;
                     BEGIN NOOP;
                   }
                   return(START_ANOPT);
                 }
                 else if (all_opt) {
                   got_all_opt = TRUE;
                   all_opt = FALSE;
                   return(START_ALLOPT);
                 }
                 else {
                   return(LBRAK);
                 }
               }

               /* a close bracket ] */
{rbrak}    { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(t_RBRAK):", yytext);
                 }
                 if (got_opt_item) {
                   got_opt_item = FALSE;
                   return(END_ITEM_BRAK);
                 }
                 else if (got_opt_param) {
                   got_opt_param = FALSE;
                   return(END_ANOPT);
                 }
                 else if (got_all_opt) {
                   got_all_opt = FALSE;
                   return(END_ALLOPT);
                 }
                 else {
                   return(RBRAK);
                 }
               }

        /*------------------- Special characters ----------------------*/

                /* a naked hash # */
{hash} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(hash):", yytext);
                 }
                 result = lookup_entry(yytext, TEX_CHAR);
                 if (result >= 0) {                 /* found it */
                   ptr = get_mode_sym(result);
                   kind = command_type(ptr);
                   yylval.pos = ptr;
                   return(kind);
                 }
                 else {
                   yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as a special character)");
                   }
                   return(OTHER);
                 }
              }

                /* a naked dollar $ */
{dollar} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(dollar):", yytext);
                   if (got_a_dollar) { print_debug_1s("(as t_END_DOLLAR)"); }
                   else { print_debug_1s("(as t_BEGIN_DOLLAR)"); }
                 }
                 if (got_a_dollar) {          /* a 'closing' $ */
                   got_a_dollar = FALSE;
                   yylval.pos = get_mode_sym(pos_edol);
                   return(END_DOLLAR);
                 }
                 else {                       /* an 'opening' $ */
                   got_a_dollar = TRUE;
                   yylval.pos = get_mode_sym(pos_bdol);
                   return(BEGIN_DOLLAR);
                }
              }

                /* a naked ampersand & */
{ampersand} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(ampersand):", yytext);
                 }
                 result = lookup_entry(yytext, TEX_CHAR);
                 if (result >= 0) {                 /* found it */
                   ptr = get_mode_sym(result);
                   kind = command_type(ptr);
                   yylval.pos = ptr;
                   return(kind);
                 }
                 else {
                   yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as a special character)");
                   }
                   return(OTHER);
                 }
              }


                /* a naked twiddle ~ */
{twiddle} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(twiddle):", yytext);
                 }
                 result = lookup_entry(yytext, TEX_CHAR);
                 if (result >= 0) {                 /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 else {
                   yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as a special character)");
                   }
                   return(OTHER);
                 }
              }

                /* a naked underscore _ */
{underscore} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(underscore):", yytext);
                 }
                 result = lookup_entry(yytext, TEX_CHAR);
                 if (result >= 0) {                 /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 else {
                   yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as a special character)");
                   }
                   return(OTHER);
                 }
              }

                /* a naked caret ^ */
{caret} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(caret):", yytext);
                 }
                 result = lookup_entry(yytext, TEX_CHAR);
                 if (result >= 0) {                 /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 else {
                   yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as a special character)");
                   }
                   return(OTHER);
                 }
              }

                /* a naked percent % */
{percent} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(percent):", yytext);
                 }
                 result = lookup_entry(yytext, TEX_CHAR);
                 if (result >= 0) {                 /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 else {
                   yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as a special character)");
                   }
                   return(OTHER);
                 }
              }

                /* a naked at @ */
{at} { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD1) {
                   print_debug_2s("(at):", yytext);
                 }
                 result = lookup_entry(yytext, TEX_CHAR);
                 if (result >= 0) {                 /* found it */
                   ptr = get_mode_sym(result);
                   yylval.pos = ptr;
                   kind = command_type(ptr);
                   return(kind);
                 }
                 else {
                   yylval.string = strsave(yytext);
                   if (LDEBUG > LD1) {
                     print_debug_1s("(as t_OTHER)");
                   }
                   if (LDEBUG > LD0) {
                     print_debug_undef(yylval.string, " (as a special character)");
                   }
                   return(OTHER);
                 }
              }



                    /* name (alphabetic string(*) ) */
{name}        { catl(yyleng, yytext);
                 nl_count = 0;
                 yylval.string = strsave(yytext);
                 if (LDEBUG > LD1) {
                   print_debug_2s("(t_NAME):", yytext);
                 }
                 return(NAME);
               }

                    /* integer (digit string) */
{integer}        { catl(yyleng, yytext);
                 nl_count = 0;
                 yylval.string = strsave(yytext);
                 if (LDEBUG > LD2) {
                   print_debug_2s("(t_INTEGER):", yytext);
                 }
                 return(INTEGER);
               }

                    /* real (digits with one period) */
{real}          { catl(yyleng, yytext);
                 nl_count = 0;
                 yylval.string = strsave(yytext);
                 if (LDEBUG > LD2) {
                   print_debug_2s("(t_REAL):", yytext);
                 }
                 return(REAL);
               }


                /* a comma */
{comma}         { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD2) {
                   print_debug_2s("(t_COMMA):", yytext);
                 }
                 return(COMMA);
               }

                /* left parenthesis */
{lparen}        { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD2) {
                   print_debug_2s("(t_LPAREN):", yytext);
                 }
                 if (opt_coord) {
                   got_opt_coord = TRUE;
                   opt_coord = FALSE;
                   return(START_COORD);
                 }
                 else {
                   return(LPAREN);
                 }
               }

                /* right parenthesis */
{rparen}        { catl(yyleng, yytext);
                 nl_count = 0;
                 if (LDEBUG > LD2) {
                   print_debug_2s("(t_RPAREN):", yytext);
                 }
                 if (got_opt_coord) {
                   got_opt_coord = FALSE;
                   return(END_COORD);
                 }
                 else {
                   return(RPAREN);
                 }
               }



               /* whitespace (except newline) print it out */
[ \t]+    { catl(yyleng, yytext);
                 if (LDEBUG > LD4) {
                   print_debug_2s("(ws):", yytext);
                 }
                 if (collapse_ws) {    /* collapse whitespace */
                   myprint(a_space);
                 }
                 else {
                   myprint(yytext);
                 }
               }

               /* newline with leading and trailing spaces */
               /* 7/96  changed to enable paragraphs outside pretty mode */
{ws}*{newline}{ws}*       { catl(yyleng, yytext);
                 nl_count++;
                /* yylval.string = strsave(yytext); */
                 do_newline();
                 if (LDEBUG > LD1) {
                   fprintf(filerr, "\n LD(newline): next line is %d\n", lineno);
                   fflush(filerr);
                 }
                 if (!pretty_print) {       /* not pretty printing */
                   myprint(yytext);
                   if (nl_count == 2) {     /* 6/96 added this */
                     yylval.pos = get_mode_sym(pos_para);
                     return(PARAGRAPH);
                   }
                 }
                 else {
                   if (nl_count == 2) {      /* (6/96 changed from >= 2 to == 2) a paragraph break */
                     yylval.pos = get_mode_sym(pos_para);
                     return(PARAGRAPH);
                   }
                   else {                    /* treat as space */
                     myprint(a_space);
                   }
                 }
               }



         /*----------- WHEN ALL ELSE FAILS --------------------*/

                /* end of file */
<<EOF>>        { catl(yyleng, yytext);
                if (LDEBUG > LD1) {
                  print_debug_1s("(end of file):\n");
                }
                yyerror("Lexer: Unexpected end of file");
                return(END_OF_FILE);
              }

               /* anything else */
             { catl(yyleng, yytext);
                 nl_count = 0;
                result = lookup_entry(yytext, TEX_CHAR);
                if (result >= 0) {           /* found it */
                  if (LDEBUG > LD1) {
                    print_debug_2s("(tex_char):", yytext);
                  }
                  ptr = get_mode_sym(result);
                  yylval.pos = ptr;
                  kind = command_type(ptr);
                  return(kind);
                }
                else {
                  yylval.string = strsave(yytext);
                  if (LDEBUG > LD4) {
                     print_debug_2s("(catch_all):", yytext);
                   }
                   return(OTHER);
                }
              }

%%