%{
/*      s2l.l  1.2    85/02/04       */
/* scanner for "scribe" documents.
 *
 * copyright (c) 1984 by Van Jacobson, Lawrence Berkeley Laboratory
 * This program may be freely redistributed but not for profit.  This
 * comment must remain in the program or any derivative.
 */

static char bstack[256];        /* the type of closing bracket we want */
static int bsp = 0;            /* "bracket" stack pointer */
char    matching();
%}
WS      [ \t]*
LB      ("("|"["|"{"|"<"|\'|\"|\`)
RB      (")"|"]"|"}"|">"|\'|\"|\')
%START  CS BS B C
%%
@[bB][lL][aA][nN][kK][sS][pP][aA][cC][eE]/{LB} {
                      BEGIN BS;
                      if ( lastsym=lookup(yytext) )
                             return (lastsym->s_type);
                      fprintf(stderr,"lex botch: keyword %s\n", yytext );
                      exit(1);
                      }
@[bB][eE][gG][iI][nN]{WS}{LB} return(get_env_name());
@[eE][nN][dD]{WS}{LB}   {
                      get_env_name();
                      return(END_ENV);
                      }
@[a-zA-Z0-9]+/{WS}{LB}  {
                      BEGIN CS;
                      if ( !(lastsym=lookup(yytext)) )
                             {
                             if ( kflag )
                                    fprintf(stderr,"unknown keyword %s\n",
                                           yytext );
                             lastsym = enter( yytext, KW_REP, &yytext[1] );
                             }
                      return (lastsym->s_type);
                      }
@[a-zA-Z0-9]+          return(COMMAND);
@\+/{WS}{LB}           {
                      BEGIN CS;
                      return(SUP);
                      }
@\-/{WS}{LB}           {
                      BEGIN CS;
                      return(SUB);
                      }
<CS>{WS}               ;
<CS>{LB}               {
                      bstack[++bsp] = matching(*yytext);
                      BEGIN C;
                      return(LBRACK);
                      }
<BS>{WS}               ;
<BS>{LB}               {
                      bstack[++bsp] = matching(*yytext);
                      BEGIN B;
                      return(LBRACK);
                      }
<B,C>{RB}              {
                      if ( bstack[bsp] == *yytext ) {
                             if ( --bsp <= 0 )
                                    BEGIN 0;
                             return(RBRACK);
                             }
                      return( (*yytext=='}'||*yytext=='"')? *yytext : CHAR );
                      }
<B>[iI][nN][cC][hH][eE][sS]     { return(INCHES); }
@\\                   return(TAB);
@>                    return(RJUST);
@=                    return(CENTER);
@\\{WS}@=              return(CENTER);
@"^"                  return(SETTAB);
@\\{WS}@=/{WS}\n        ;
@=/{WS}\n              ;
@\\/{WS}\n             ;
@;                    ;
@~                    return(STILDE);
@_                    return(HYPHEN);
@" "                  return(NPSPACE);
@@                    return('@');
@"*"                  return(LBREAK);
@\.[ \t]+              return(POINT);
@\.{WS}/\n             return(POINT);
[<>|{}#$%&~_^\\"]       return(*yytext);
.                     return(CHAR);
^[      ]*\n          {
                      inputline++;
                      return(BLANKLINE);
                      }
[       ]*\n          {
                      inputline++;
                      return('\n');
                      }
%%
yywrap() {
        return (1);
}

/* get the "name" part of an environment spec & discard any optional
 * parameters.  The name is added to the symbol table if it isn't
 * already there.  At the time we call this routine, we've matched
 * either "@begin{LB}" or "@end{LB}".  We gobble input until we find
 * the matching right bracket.
 */
get_env_name()
{
        char   ename[128];
        char   c;
        char   *nm=ename;
        char   mb = matching( yytext[yyleng-1] );

        /* get the name */
        while ( isalnum( c=input() ) )
               *nm++ = c;
        *nm = '\0';

        /* discard everything else up to the closing bracket */
        while ( c != mb )
               c = input();

        /* lookup and/or add the env name */
        if ( ! (lastsym = lookup(ename)) )
               {
               if ( kflag )
                      fprintf(stderr,"unknown environment %s\n", ename );
               lastsym = enter( ename, ENV_REP, ename );
               }
        return(lastsym->s_type);
}

/* return the right bracket character that matches the given left bracket
 * character.
 */
char matching(lb)
char lb;
{
        switch(lb) {

        case '(':  return(')');
        case '[':  return(']');
        case '{':  return('}');
        case '<':  return('>');
        case '"':  return('"');
        case '\'':  return('\'');
        case '`':  return('\'');
        default:
               fprintf(stderr,"matching botch: '%c'\n", lb );
               exit(1);
        }
}