

































































/*
 * Copyright (c) 1978 Charles H. Forsyth
 */

/*
 *              W A R N I N G
 *
 * This file is NOT identical with ytab.c.  Several changes which were
 * made directly to ytab.c have not been made to lex.y
 *
 * If you have access to yacc and rebuild ytab.c from lex.y, it is
 * essential that you compare the current ytab.c with the new version,
 * incorporating the necessary changes.
 */

/*
 * lex -- grammar/lexical analyser
 */

%{
#include <stdio.h>
#include "lexlex.h"
char    copr[]  "Copyright (c) 1978 Charles H. Forsyth";
struct des {
        struct nfa *d_start;
        struct nfa *d_final;
};
struct nlist {
        struct  nlist   *nl_next;
        struct  nfa     *nl_base;
        struct  nfa     *nl_end;
        struct  nfa     *nl_start;
        struct  nfa     *nl_final;
        char    *nl_name;
} *nlist;
int     strlen;
extern  struct  nfa     *elem();
extern  struct  des     *newdp();
extern  struct  nlist   *lookup();
extern  char            *spccl();
%}
%term NAME CCLASS STRING CONCAT

%left ';'
%left '='
%left '/'
%left '|'
%left '(' NAME STRING CCLASS
%left CONCAT
%left '*'
%%
%{
        struct nfa *np, *nbase;
        char *cp;
        struct des *dp;
        struct trans *tp;
        struct nlist *nl;
        int i, c;
%}
lexfile:
        auxiliary_section translation_section
|




;

auxiliary_section:
        auxiliaries '%' '%'
|       '%' '%'
;

auxiliaries:
        auxiliaries auxiliary
|       auxiliary
;

auxiliary:
        namedef '=' regexp ';' ={
                dp = $3;
                nl = $1;
                np = nl->nl_base;
                nl->nl_start = dp->d_start;
                nl->nl_final = dp->d_final;
                nl->nl_end = nfap;
                printf("NFA for %s\n", nl->nl_name);
                nfaprint(dp->d_start, nl->nl_base);
                nbase = lalloc(i = nl->nl_end-nl->nl_base, sizeof(*nbase),
                        "nfa storage");
                copynfa(nl, nbase, dp);
                nl->nl_start = dp->d_start;
                nl->nl_final = dp->d_final;
                nl->nl_end = nbase+i;
                nl->nl_base = nbase;
                nfap = np;
                ignore = spccl(nl->nl_name, "ignore", dp);
                breakc = spccl(nl->nl_name, "break", dp);
                illeg = spccl(nl->nl_name, "illegal", dp);
        }
|       '%' '{'         ={ copycode(); }
;

namedef:
        NAME    ={
                $$ = lookup($1);
                $$->nl_base = nfap;
                if ($$->nl_start)
                        error("%s redefined", $$->nl_name);
        }
;

name:
        NAME    ={ $$ = lookup($1); }
;

regexp:
        CCLASS ={
                np = elem(CCL, $1);
                $$ = newdp(np, np->n_succ[0] = elem(FIN));
        }
|       STRING ={
                cp = $1;
                if (strlen == 0) {
                        np = elem(EPSILON);
                        $$ = newdp(np, np->n_succ[0] = elem(FIN));
                        return;
                }




                $$ = np = elem(*cp++);
                while (--strlen > 0)
                        np = np->n_succ[0] = elem(*cp++);
                $$ = newdp($$, np->n_succ[0] = elem(FIN));
        }
|       name    ={
                if ((nl = $1)->nl_end == 0) {
                        error("%s not defined", nl->nl_name);
                        nl->nl_base = nl->nl_end = elem(FIN);
                        nl->nl_start = nl->nl_final = nl->nl_base;
                }
                $$ = dp = lalloc(1, sizeof(*dp), "dfa input");
                nbase = nfap;
                i = nl->nl_end-nl->nl_base;
                if ((nfap += i) >= &nfa[MAXNFA]) {
                        error("Out of NFA nodes");
                        exit(1);
                }
                copynfa(nl, nbase, dp);
        }
|       regexp '*' ={
                $$ = dp = $1;
                dp->d_start = newnfa(EPSILON, np = dp->d_start, 0);
                dp->d_final->n_char = EPSILON;
                dp->d_final->n_succ[0] = np;
                dp->d_final->n_succ[1] = np = elem(FIN);
                dp->d_start->n_succ[1] = np;
                dp->d_final = np;
        }
|       regexp '|' regexp ={
                $$ = dp = $1;
                dp->d_start = newnfa(EPSILON, dp->d_start, $3->d_start);
                dp->d_final->n_char = EPSILON;
                dp->d_final = dp->d_final->n_succ[0] = np = elem(FIN);
                dp = $3;
                dp->d_final->n_char = EPSILON;
                dp->d_final->n_succ[0] = np;
                cfree($3);
        }
|       regexp regexp %prec CONCAT ={
                $$ = $1;
                dp = $2;
                np = $$->d_final;
                $$->d_final = dp->d_final;
                np->n_char = dp->d_start->n_char;
                np->n_ccl = dp->d_start->n_ccl;
                np->n_succ[0] = dp->d_start->n_succ[0];
                np->n_succ[1] = dp->d_start->n_succ[1];
                cfree($2);
        }
|       '(' regexp ')' ={ $$ = $2; }
;

translation_section:
        translations ={
                ending();
        trans1:
                printf("\nNFA for complete syntax\n");
                printf("state 0\n");
                for (tp = trans; tp < transp; tp++)
                        printf("\tepsilon\t%d\n", tp->t_start-nfa);
                for (tp = trans; tp < transp; tp++)




                        nfaprint(tp->t_start, nfa);
                dfabuild();
                dfamin();
                dfaprint();
                dfawrite();
                stats();
        }
|       ={ goto trans1; }
;

translations:
        translations translation
|       llactr translation
;

llactr:
        ={
                llactr();
        }
;

translation:
        pattern action ={ dp = $1;  newtrans(dp->d_start, dp->d_final); }
|       '%' '{'         ={ copycode(); }
|       '%' '%'         ={
                ending();
                while ((c = get()) != EOF)
                        putc(c, llout);
        }
;

action:
        '{'     ={ action(); }
;

pattern:
        regexp '/' regexp ={
                if (nlook >= NBPW)
                        error("More than %d translations with lookahead",NBPW);
                $$ = dp = $1;
                np = dp->d_final;
                np->n_char = EPSILON;
                np->n_flag |= LOOK;
                np->n_succ[0] = $3->d_start;
                dp->d_final = $3->d_final;
                np->n_look = nlook;
                dp->d_final->n_look = nlook++;
                dp->d_final->n_flag |= FLOOK;
                cfree($3);
        }
|       regexp
;

%%
/*
 * Lexical analyser
 * (it isn't done with lex...)
 */
char    buffer[150];

yylex()
{




        register c;
        register char *cp;
        int lno;

        if (yyline == 0)
                yyline++;
loop:
        c = get();
        if (isupper(c)) {
                name(c);
                for (cp = yylval; c = *cp; cp++)
                        if (isupper(c))
                                *cp = tolower(c);
                return(STRING);
        } else if (islower(c) || c == '_') {
                name(c);
                return(NAME);
        }
        switch (c) {
        case EOF:
                return(0);

        case '[':
                return(cclass());

        case '(':
        case ')':
        case '{':
        case '}':
        case '*':
        case '|':
        case '=':
        case ';':
        case '%':
                return(c);

        case '/':
                if ((c = get()) != '*') {
                        unget(c);
                        return('/');
                }
                lno = yyline;
                for (; c != EOF; c = get())
                        if (c == '*')
                                if ((c = get()) == '/')
                                        goto loop; else
                                        unget(c);
                yyline = lno;
                error("End of file in comment");

        case '\'':
        case '"':
                yylval = buffer;
                string(c);
                return(STRING);

        case '\n':
        case ' ':
        case '\t':
                goto loop;

        default:




                yylval = buffer;
                if (c == '\\') {
                        unget(c);
                        c = mapch(EOF);
                }
                buffer[0] = c;
                buffer[1] = 0;
                strlen = 1;
                return(STRING);
        }
}

char    ccl[(NCHARS+1)/NBPC];

cclass()
{
        register c, i, lc;
        int compl;

        compl = 0;
        for (i = 0; i < sizeof ccl; i++)
                ccl[i] = 0;
        if ((c = get()) == '^')
                compl++; else
                unget(c);
        lc = -1;
        while ((c = mapc(']')) != EOF) {
                if (c == '-' && lc >= 0) {
                        if ((c = mapc(']')) == EOF)
                                break;
                        for (i = lc; i <= c; i++)
                                ccl[i/NBPC] |= 1<<(i%NBPC);
                        lc = -1;
                        continue;
                }
                ccl[c/NBPC] |= 1<<(c%NBPC);
                lc = c;
        }
        if (compl) {
                for (i = 0; i < sizeof ccl; i++)
                        ccl[i] ^= -1;
                if (aflag == 0)
                        for (i = 0200; i < (1<<NBPC); i++)
                                ccl[i/NBPC] &= ~(1 << (i%NBPC));
        }
        yylval = newccl(ccl);
        return(CCLASS);
}

string(ec)
{
        register char *cp;
        register c;

        for (cp = buffer; (c = mapc(ec)) != EOF;)
                *cp++ = c;
        *cp = 0;
        strlen = cp-buffer;
}

mapc(ec)
{




        register c, v, i;

        if ((c = get()) == ec)
                return(EOF);
        switch(c) {
        case EOF:
                error("End of file in string");
                return(c);

        case '\\':
                if ((c = get()) >= '0' && c <= '7') {
                        i = 0;
                        for (v = 0; c>='0' && c<='7' && i++<3; c = get())
                                v = v*010 + c-'0';
                        unget(c);
                        return(v&0377);
                }
                switch (c) {
                case 'n':
                        return('\n');

                case 't':
                        return('\t');

                case 'b':
                        return('\b');

                case 'r':
                        return('\r');

                case '\n':
                        yyline++;
                        return(mapc(ec));
                }

        default:
                return(c);
        }
}

name(c)
register c;
{
        register char *cp;

        for (yylval=cp=buffer; isalpha(c) || isdigit(c) || c=='_'; c=get())
                *cp++ = c;
        *cp = 0;
        strlen = cp-buffer;
        unget(c);
}

/*
 * Miscellaneous functions
 * used only by lex.y
 */
struct nfa *
elem(k, v)
{
        struct nfa *fp;

        fp = newnfa(k, 0, 0);




        if (k == CCL)
                fp->n_ccl = v;
        return(fp);
}

struct des *
newdp(st, fi)
struct nfa *st, *fi;
{
        register struct des *dp;

        dp = lalloc(1, sizeof(*dp), "dfa input");
        dp->d_start = st;
        dp->d_final = fi;
        return(dp);
}

action()
{
        register c;
        int lno, lev;

        newcase(transp-trans);
        lno = yyline;
        lev = 0;
        for (; (c = get()) != EOF && (c != '}' || lev); putc(c, llout))
                if (c == '{')
                        lev++;
                else if (c == '}')
                        lev--;
                else if (c == '\'' || c == '"') {
                        putc(c, llout);
                        skipstr(c);
                }
        fprintf(llout, "\n\tbreak;\n");
        if (c == EOF) {
                yyline = lno;
                error("End of file in action");
        }
}

skipstr(ec)
register ec;
{
        register c;

        while ((c = get()) != ec && c != EOF) {
                putc(c, llout);
                if (c == '\\' && (c = get()) != EOF)
                        putc(c, llout);
        }
}


copycode()
{
        int lno;
        register c;

        setline();
        lno = yyline;
        for (; (c = get()) != EOF; putc(c, llout))




                if (c == '%') {
                        if ((c = get()) == '}')
                                return;
                        unget(c);
                        c = '%';
                }
        yyline = lno;
        error("Incomplete %{ declaration");
        exit(1);
}

struct nlist *
lookup(s)
register char *s;
{
        register struct nlist *nl;
        register char *cp;
        int i;

        for (nl = nlist; nl; nl = nl->nl_next)
                if (streq(s, nl->nl_name))
                        return(nl);
        nl = lalloc(1, sizeof(*nl), "namelist");
        nl->nl_start = nl->nl_end = nl->nl_base = nl->nl_end = 0;
        nl->nl_next = nlist;
        nlist = nl;
        i = 0;
        for (cp = s; *cp++;)
                i++;
        nl->nl_name = cp = lalloc(i+1, sizeof(*cp), "namelist");
        while (*cp++ = *s++)
                ;
        return(nl);
}

copynfa(nl, nbase, dp)
struct nlist *nl;
struct des *dp;
struct nfa *nbase;
{
        register struct nfa *np, *ob;
        register j;
        int i, ix;

        ob = nl->nl_base;
        i = nl->nl_end-ob;
        copy(ob, sizeof(*np), i, nbase);
        for (np = nbase; i-- > 0; np++) {
                np->n_flag &= ~NPRT;
                for (j = 0; j < 2; j++)
                        if (np->n_succ[j])
                                np->n_succ[j] = (np->n_succ[j]-ob)+nbase;
        }
        dp->d_start = (nl->nl_start-ob)+nbase;
        dp->d_final = (nl->nl_final-ob)+nbase;
}

char *
spccl(nm, isit, dp)
char *nm, *isit;
register struct des *dp;
{




        if (!streq(nm, isit))
                return(0);
        if (dp->d_start->n_char == CCL &&
            dp->d_start->n_succ[0] == dp->d_final)
                return(dp->d_start->n_ccl);
        error("Illegal %s class", isit);
        return(0);
}

get()
{
        register c;

        if ((c = getc(stdin)) == '\n')
                yyline++;
        return(c);
}

unget(c)
register c;
{
        if (c == '\n')
                yyline--;
        ungetc(c, stdin);
}

error(s)
char *s;
{
        if (yyline)
                fprintf(stderr, "%d: ", yyline);
        fprintf(stderr, "%r", &s);
        if (yychar > 256)
                fprintf(stderr, " near `%s'", yysterm[yychar-256]);
        else if (yychar < 256 && yychar > 0)
                fprintf(stderr, " near `%c'", yychar);
        fprintf(stderr, "\n");
}
se if (yychar < 256 && yychar > 0)
                fprintf(stderr, " near `%c'", yych