diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 12:33:43 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 12:33:43 +0000 |
commit | f9ab90d9d6d02989a075d0f0074496d5b1045e4b (patch) | |
tree | add7e996bac5289cdc55e6935750c352505560a9 /usr.bin/yacc | |
parent | be22b15ae2ff8d7fe06b6e14fddf0c5b444a95da (diff) | |
download | FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.zip FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.tar.gz |
BSD 4.4 Lite Usr.bin Sources
Diffstat (limited to 'usr.bin/yacc')
29 files changed, 12526 insertions, 0 deletions
diff --git a/usr.bin/yacc/ACKNOWLEDGEMENTS b/usr.bin/yacc/ACKNOWLEDGEMENTS new file mode 100644 index 0000000..b66bb25 --- /dev/null +++ b/usr.bin/yacc/ACKNOWLEDGEMENTS @@ -0,0 +1,25 @@ + Berkeley Yacc owes much to the unflagging efforts of Keith Bostic. +His badgering kept me working on it long after I was ready to quit. + + Berkeley Yacc is based on the excellent algorithm for computing LALR(1) +lookaheads developed by Tom Pennello and Frank DeRemer. The algorithm is +described in their almost impenetrable article in TOPLAS 4,4. + + Finally, much of the credit for the latest version must go to those +who pointed out deficiencies of my earlier releases. Among the most +prolific contributors were + + Benson I. Margulies + Dave Gentzel + Antoine Verheijen + Peter S. Housel + Dale Smith + Ozan Yigit + John Campbell + Bill Sommerfeld + Paul Hilfinger + Gary Bridgewater + Dave Bakken + Dan Lanciani + Richard Sargent + Parag Patel diff --git a/usr.bin/yacc/Makefile b/usr.bin/yacc/Makefile new file mode 100644 index 0000000..71633a3 --- /dev/null +++ b/usr.bin/yacc/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 5.3 (Berkeley) 5/12/90 + +PROG= yacc +SRCS= closure.c error.c lalr.c lr0.c main.c mkpar.c output.c reader.c \ + skeleton.c symtab.c verbose.c warshall.c +MAN1= yacc.0 yyfix.0 + +beforeinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/yyfix.sh ${DESTDIR}${BINDIR}/yyfix + +.include <bsd.prog.mk> diff --git a/usr.bin/yacc/NEW_FEATURES b/usr.bin/yacc/NEW_FEATURES new file mode 100644 index 0000000..b030c62 --- /dev/null +++ b/usr.bin/yacc/NEW_FEATURES @@ -0,0 +1,46 @@ + The -r option has been implemented. The -r option tells Yacc to +put the read-only tables in y.tab.c and the code and variables in +y.code.c. Keith Bostic asked for this option so that :yyfix could be +eliminated. + + The -l and -t options have been implemented. The -l option tells +Yacc not to include #line directives in the code it produces. The -t +option causes debugging code to be included in the compiled parser. + + The code for error recovery has been changed to implement the same +algorithm as AT&T Yacc. There will still be differences in the way +error recovery works because AT&T Yacc uses more default reductions +than Berkeley Yacc. + + The environment variable TMPDIR determines the directory where +temporary files will be created. If TMPDIR is defined, temporary files +will be created in the directory whose pathname is the value of TMPDIR. +By default, temporary files are created in /tmp. + + The keywords are now case-insensitive. For example, %nonassoc, +%NONASSOC, %NonAssoc, and %nOnAsSoC are all equivalent. + + Commas and semicolons that are not part of C code are treated as +commentary. + + Line-end comments, as in BCPL, are permitted. Line-end comments +begin with // and end at the next end-of-line. Line-end comments are +permitted in C code; they are converted to C comments on output. + + The form of y.output files has been changed to look more like +those produced by AT&T Yacc. + + A new kind of declaration has been added. The form of the declaration +is + + %ident string + +where string is a sequence of characters begining with a double quote +and ending with either a double quote or the next end-of-line, whichever +comes first. The declaration will cause a #ident directive to be written +near the start of the output file. + + If a parser has been compiled with debugging code, that code can be +enabled by setting an environment variable. If the environment variable +YYDEBUG is set to 0, debugging output is suppressed. If it is set to 1, +debugging output is written to standard output. diff --git a/usr.bin/yacc/NOTES b/usr.bin/yacc/NOTES new file mode 100644 index 0000000..9db3c96 --- /dev/null +++ b/usr.bin/yacc/NOTES @@ -0,0 +1,9 @@ +Berkeley Yacc reflects its origins. The reason so many routines +use exactly six register variables is that Berkeley Yacc was +developed on a VAX using PCC. PCC placed at most six variables +in registers. I went to considerable effort to find which six +variables most belonged in registers. Changes in machines and +compilers make that effort worthless, perhaps even harmful. + +The code contains many instances where address calculations are +performed in particular ways to optimize the code for the VAX. diff --git a/usr.bin/yacc/README b/usr.bin/yacc/README new file mode 100644 index 0000000..091f233 --- /dev/null +++ b/usr.bin/yacc/README @@ -0,0 +1,23 @@ + Berkeley Yacc is an LALR(1) parser generator. Berkeley Yacc has been made +as compatible as possible with AT&T Yacc. Berkeley Yacc can accept any input +specification that conforms to the AT&T Yacc documentation. Specifications +that take advantage of undocumented features of AT&T Yacc will probably be +rejected. + + Berkeley Yacc is distributed with no warranty whatever. The code is certain +to contain errors. Neither the author nor any contributor takes responsibility +for any consequences of its use. + + Berkeley Yacc is in the public domain. The data structures and algorithms +used in Berkeley Yacc are all either taken from documents available to the +general public or are inventions of the author. Anyone may freely distribute +source or binary forms of Berkeley Yacc whether unchanged or modified. +Distributers may charge whatever fees they can obtain for Berkeley Yacc. +Programs generated by Berkeley Yacc may be distributed freely. + + Please report bugs to + + robert.corbett@eng.Sun.COM + +Include a small example if possible. Please include the banner string from +skeleton.c with the bug report. Do not expect rapid responses. diff --git a/usr.bin/yacc/closure.c b/usr.bin/yacc/closure.c new file mode 100644 index 0000000..5f63c5f --- /dev/null +++ b/usr.bin/yacc/closure.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)closure.c 5.3 (Berkeley) 5/24/93"; +#endif /* not lint */ + +#include "defs.h" + +short *itemset; +short *itemsetend; +unsigned *ruleset; + +static unsigned *first_derives; +static unsigned *EFF; + + +set_EFF() +{ + register unsigned *row; + register int symbol; + register short *sp; + register int rowsize; + register int i; + register int rule; + + rowsize = WORDSIZE(nvars); + EFF = NEW2(nvars * rowsize, unsigned); + + row = EFF; + for (i = start_symbol; i < nsyms; i++) + { + sp = derives[i]; + for (rule = *sp; rule > 0; rule = *++sp) + { + symbol = ritem[rrhs[rule]]; + if (ISVAR(symbol)) + { + symbol -= start_symbol; + SETBIT(row, symbol); + } + } + row += rowsize; + } + + reflexive_transitive_closure(EFF, nvars); + +#ifdef DEBUG + print_EFF(); +#endif +} + + +set_first_derives() +{ + register unsigned *rrow; + register unsigned *vrow; + register int j; + register unsigned k; + register unsigned cword; + register short *rp; + + int rule; + int i; + int rulesetsize; + int varsetsize; + + rulesetsize = WORDSIZE(nrules); + varsetsize = WORDSIZE(nvars); + first_derives = NEW2(nvars * rulesetsize, unsigned) - ntokens * rulesetsize; + + set_EFF(); + + rrow = first_derives + ntokens * rulesetsize; + for (i = start_symbol; i < nsyms; i++) + { + vrow = EFF + ((i - ntokens) * varsetsize); + k = BITS_PER_WORD; + for (j = start_symbol; j < nsyms; k++, j++) + { + if (k >= BITS_PER_WORD) + { + cword = *vrow++; + k = 0; + } + + if (cword & (1 << k)) + { + rp = derives[j]; + while ((rule = *rp++) >= 0) + { + SETBIT(rrow, rule); + } + } + } + + vrow += varsetsize; + rrow += rulesetsize; + } + +#ifdef DEBUG + print_first_derives(); +#endif + + FREE(EFF); +} + + +closure(nucleus, n) +short *nucleus; +int n; +{ + register int ruleno; + register unsigned word; + register unsigned i; + register short *csp; + register unsigned *dsp; + register unsigned *rsp; + register int rulesetsize; + + short *csend; + unsigned *rsend; + int symbol; + int itemno; + + rulesetsize = WORDSIZE(nrules); + rsp = ruleset; + rsend = ruleset + rulesetsize; + for (rsp = ruleset; rsp < rsend; rsp++) + *rsp = 0; + + csend = nucleus + n; + for (csp = nucleus; csp < csend; ++csp) + { + symbol = ritem[*csp]; + if (ISVAR(symbol)) + { + dsp = first_derives + symbol * rulesetsize; + rsp = ruleset; + while (rsp < rsend) + *rsp++ |= *dsp++; + } + } + + ruleno = 0; + itemsetend = itemset; + csp = nucleus; + for (rsp = ruleset; rsp < rsend; ++rsp) + { + word = *rsp; + if (word) + { + for (i = 0; i < BITS_PER_WORD; ++i) + { + if (word & (1 << i)) + { + itemno = rrhs[ruleno+i]; + while (csp < csend && *csp < itemno) + *itemsetend++ = *csp++; + *itemsetend++ = itemno; + while (csp < csend && *csp == itemno) + ++csp; + } + } + } + ruleno += BITS_PER_WORD; + } + + while (csp < csend) + *itemsetend++ = *csp++; + +#ifdef DEBUG + print_closure(n); +#endif +} + + + +finalize_closure() +{ + FREE(itemset); + FREE(ruleset); + FREE(first_derives + ntokens * WORDSIZE(nrules)); +} + + +#ifdef DEBUG + +print_closure(n) +int n; +{ + register short *isp; + + printf("\n\nn = %d\n\n", n); + for (isp = itemset; isp < itemsetend; isp++) + printf(" %d\n", *isp); +} + + +print_EFF() +{ + register int i, j; + register unsigned *rowp; + register unsigned word; + register unsigned k; + + printf("\n\nEpsilon Free Firsts\n"); + + for (i = start_symbol; i < nsyms; i++) + { + printf("\n%s", symbol_name[i]); + rowp = EFF + ((i - start_symbol) * WORDSIZE(nvars)); + word = *rowp++; + + k = BITS_PER_WORD; + for (j = 0; j < nvars; k++, j++) + { + if (k >= BITS_PER_WORD) + { + word = *rowp++; + k = 0; + } + + if (word & (1 << k)) + printf(" %s", symbol_name[start_symbol + j]); + } + } +} + + +print_first_derives() +{ + register int i; + register int j; + register unsigned *rp; + register unsigned cword; + register unsigned k; + + printf("\n\n\nFirst Derives\n"); + + for (i = start_symbol; i < nsyms; i++) + { + printf("\n%s derives\n", symbol_name[i]); + rp = first_derives + i * WORDSIZE(nrules); + k = BITS_PER_WORD; + for (j = 0; j <= nrules; k++, j++) + { + if (k >= BITS_PER_WORD) + { + cword = *rp++; + k = 0; + } + + if (cword & (1 << k)) + printf(" %d\n", j); + } + } + + fflush(stdout); +} + +#endif diff --git a/usr.bin/yacc/defs.h b/usr.bin/yacc/defs.h new file mode 100644 index 0000000..e5e96d2 --- /dev/null +++ b/usr.bin/yacc/defs.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)defs.h 5.6 (Berkeley) 5/24/93 + */ + +#include <assert.h> +#include <ctype.h> +#include <stdio.h> + + +/* machine-dependent definitions */ +/* the following definitions are for the Tahoe */ +/* they might have to be changed for other machines */ + +/* MAXCHAR is the largest unsigned character value */ +/* MAXSHORT is the largest value of a C short */ +/* MINSHORT is the most negative value of a C short */ +/* MAXTABLE is the maximum table size */ +/* BITS_PER_WORD is the number of bits in a C unsigned */ +/* WORDSIZE computes the number of words needed to */ +/* store n bits */ +/* BIT returns the value of the n-th bit starting */ +/* from r (0-indexed) */ +/* SETBIT sets the n-th bit starting from r */ + +#define MAXCHAR 255 +#define MAXSHORT 32767 +#define MINSHORT -32768 +#define MAXTABLE 32500 +#define BITS_PER_WORD 32 +#define WORDSIZE(n) (((n)+(BITS_PER_WORD-1))/BITS_PER_WORD) +#define BIT(r, n) ((((r)[(n)>>5])>>((n)&31))&1) +#define SETBIT(r, n) ((r)[(n)>>5]|=((unsigned)1<<((n)&31))) + + +/* character names */ + +#define NUL '\0' /* the null character */ +#define NEWLINE '\n' /* line feed */ +#define SP ' ' /* space */ +#define BS '\b' /* backspace */ +#define HT '\t' /* horizontal tab */ +#define VT '\013' /* vertical tab */ +#define CR '\r' /* carriage return */ +#define FF '\f' /* form feed */ +#define QUOTE '\'' /* single quote */ +#define DOUBLE_QUOTE '\"' /* double quote */ +#define BACKSLASH '\\' /* backslash */ + + +/* defines for constructing filenames */ + +#define CODE_SUFFIX ".code.c" +#define DEFINES_SUFFIX ".tab.h" +#define OUTPUT_SUFFIX ".tab.c" +#define VERBOSE_SUFFIX ".output" + + +/* keyword codes */ + +#define TOKEN 0 +#define LEFT 1 +#define RIGHT 2 +#define NONASSOC 3 +#define MARK 4 +#define TEXT 5 +#define TYPE 6 +#define START 7 +#define UNION 8 +#define IDENT 9 + + +/* symbol classes */ + +#define UNKNOWN 0 +#define TERM 1 +#define NONTERM 2 + + +/* the undefined value */ + +#define UNDEFINED (-1) + + +/* action codes */ + +#define SHIFT 1 +#define REDUCE 2 + + +/* character macros */ + +#define IS_IDENT(c) (isalnum(c) || (c) == '_' || (c) == '.' || (c) == '$') +#define IS_OCTAL(c) ((c) >= '0' && (c) <= '7') +#define NUMERIC_VALUE(c) ((c) - '0') + + +/* symbol macros */ + +#define ISTOKEN(s) ((s) < start_symbol) +#define ISVAR(s) ((s) >= start_symbol) + + +/* storage allocation macros */ + +#define CALLOC(k,n) (calloc((unsigned)(k),(unsigned)(n))) +#define FREE(x) (free((char*)(x))) +#define MALLOC(n) (malloc((unsigned)(n))) +#define NEW(t) ((t*)allocate(sizeof(t))) +#define NEW2(n,t) ((t*)allocate((unsigned)((n)*sizeof(t)))) +#define REALLOC(p,n) (realloc((char*)(p),(unsigned)(n))) + + +/* the structure of a symbol table entry */ + +typedef struct bucket bucket; +struct bucket +{ + struct bucket *link; + struct bucket *next; + char *name; + char *tag; + short value; + short index; + short prec; + char class; + char assoc; +}; + + +/* the structure of the LR(0) state machine */ + +typedef struct core core; +struct core +{ + struct core *next; + struct core *link; + short number; + short accessing_symbol; + short nitems; + short items[1]; +}; + + +/* the structure used to record shifts */ + +typedef struct shifts shifts; +struct shifts +{ + struct shifts *next; + short number; + short nshifts; + short shift[1]; +}; + + +/* the structure used to store reductions */ + +typedef struct reductions reductions; +struct reductions +{ + struct reductions *next; + short number; + short nreds; + short rules[1]; +}; + + +/* the structure used to represent parser actions */ + +typedef struct action action; +struct action +{ + struct action *next; + short symbol; + short number; + short prec; + char action_code; + char assoc; + char suppressed; +}; + + +/* global variables */ + +extern char dflag; +extern char lflag; +extern char rflag; +extern char tflag; +extern char vflag; +extern char *symbol_prefix; + +extern char *myname; +extern char *cptr; +extern char *line; +extern int lineno; +extern int outline; + +extern char *banner[]; +extern char *tables[]; +extern char *header[]; +extern char *body[]; +extern char *trailer[]; + +extern char *action_file_name; +extern char *code_file_name; +extern char *defines_file_name; +extern char *input_file_name; +extern char *output_file_name; +extern char *text_file_name; +extern char *union_file_name; +extern char *verbose_file_name; + +extern FILE *action_file; +extern FILE *code_file; +extern FILE *defines_file; +extern FILE *input_file; +extern FILE *output_file; +extern FILE *text_file; +extern FILE *union_file; +extern FILE *verbose_file; + +extern int nitems; +extern int nrules; +extern int nsyms; +extern int ntokens; +extern int nvars; +extern int ntags; + +extern char unionized; +extern char line_format[]; + +extern int start_symbol; +extern char **symbol_name; +extern short *symbol_value; +extern short *symbol_prec; +extern char *symbol_assoc; + +extern short *ritem; +extern short *rlhs; +extern short *rrhs; +extern short *rprec; +extern char *rassoc; + +extern short **derives; +extern char *nullable; + +extern bucket *first_symbol; +extern bucket *last_symbol; + +extern int nstates; +extern core *first_state; +extern shifts *first_shift; +extern reductions *first_reduction; +extern short *accessing_symbol; +extern core **state_table; +extern shifts **shift_table; +extern reductions **reduction_table; +extern unsigned *LA; +extern short *LAruleno; +extern short *lookaheads; +extern short *goto_map; +extern short *from_state; +extern short *to_state; + +extern action **parser; +extern int SRtotal; +extern int RRtotal; +extern short *SRconflicts; +extern short *RRconflicts; +extern short *defred; +extern short *rules_used; +extern short nunused; +extern short final_state; + +/* global functions */ + +extern char *allocate(); +extern bucket *lookup(); +extern bucket *make_bucket(); + + +/* system variables */ + +extern int errno; + + +/* system functions */ + +extern void free(); +extern char *calloc(); +extern char *malloc(); +extern char *realloc(); +extern char *strcpy(); diff --git a/usr.bin/yacc/error.c b/usr.bin/yacc/error.c new file mode 100644 index 0000000..54a49ad --- /dev/null +++ b/usr.bin/yacc/error.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)error.c 5.3 (Berkeley) 6/1/90"; +#endif /* not lint */ + +/* routines for printing error messages */ + +#include "defs.h" + + +fatal(msg) +char *msg; +{ + fprintf(stderr, "%s: f - %s\n", myname, msg); + done(2); +} + + +no_space() +{ + fprintf(stderr, "%s: f - out of space\n", myname); + done(2); +} + + +open_error(filename) +char *filename; +{ + fprintf(stderr, "%s: f - cannot open \"%s\"\n", myname, filename); + done(2); +} + + +unexpected_EOF() +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unexpected end-of-file\n", + myname, lineno, input_file_name); + done(1); +} + + +print_pos(st_line, st_cptr) +char *st_line; +char *st_cptr; +{ + register char *s; + + if (st_line == 0) return; + for (s = st_line; *s != '\n'; ++s) + { + if (isprint(*s) || *s == '\t') + putc(*s, stderr); + else + putc('?', stderr); + } + putc('\n', stderr); + for (s = st_line; s < st_cptr; ++s) + { + if (*s == '\t') + putc('\t', stderr); + else + putc(' ', stderr); + } + putc('^', stderr); + putc('\n', stderr); +} + + +syntax_error(st_lineno, st_line, st_cptr) +int st_lineno; +char *st_line; +char *st_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", syntax error\n", + myname, st_lineno, input_file_name); + print_pos(st_line, st_cptr); + done(1); +} + + +unterminated_comment(c_lineno, c_line, c_cptr) +int c_lineno; +char *c_line; +char *c_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unmatched /*\n", + myname, c_lineno, input_file_name); + print_pos(c_line, c_cptr); + done(1); +} + + +unterminated_string(s_lineno, s_line, s_cptr) +int s_lineno; +char *s_line; +char *s_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unterminated string\n", + myname, s_lineno, input_file_name); + print_pos(s_line, s_cptr); + done(1); +} + + +unterminated_text(t_lineno, t_line, t_cptr) +int t_lineno; +char *t_line; +char *t_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unmatched %%{\n", + myname, t_lineno, input_file_name); + print_pos(t_line, t_cptr); + done(1); +} + + +unterminated_union(u_lineno, u_line, u_cptr) +int u_lineno; +char *u_line; +char *u_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unterminated %%union \ +declaration\n", myname, u_lineno, input_file_name); + print_pos(u_line, u_cptr); + done(1); +} + + +over_unionized(u_cptr) +char *u_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", too many %%union \ +declarations\n", myname, lineno, input_file_name); + print_pos(line, u_cptr); + done(1); +} + + +illegal_tag(t_lineno, t_line, t_cptr) +int t_lineno; +char *t_line; +char *t_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", illegal tag\n", + myname, t_lineno, input_file_name); + print_pos(t_line, t_cptr); + done(1); +} + + +illegal_character(c_cptr) +char *c_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", illegal character\n", + myname, lineno, input_file_name); + print_pos(line, c_cptr); + done(1); +} + + +used_reserved(s) +char *s; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", illegal use of reserved symbol \ +%s\n", myname, lineno, input_file_name, s); + done(1); +} + + +tokenized_start(s) +char *s; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", the start symbol %s cannot be \ +declared to be a token\n", myname, lineno, input_file_name, s); + done(1); +} + + +retyped_warning(s) +char *s; +{ + fprintf(stderr, "%s: w - line %d of \"%s\", the type of %s has been \ +redeclared\n", myname, lineno, input_file_name, s); +} + + +reprec_warning(s) +char *s; +{ + fprintf(stderr, "%s: w - line %d of \"%s\", the precedence of %s has been \ +redeclared\n", myname, lineno, input_file_name, s); +} + + +revalued_warning(s) +char *s; +{ + fprintf(stderr, "%s: w - line %d of \"%s\", the value of %s has been \ +redeclared\n", myname, lineno, input_file_name, s); +} + + +terminal_start(s) +char *s; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", the start symbol %s is a \ +token\n", myname, lineno, input_file_name, s); + done(1); +} + + +restarted_warning() +{ + fprintf(stderr, "%s: w - line %d of \"%s\", the start symbol has been \ +redeclared\n", myname, lineno, input_file_name); +} + + +no_grammar() +{ + fprintf(stderr, "%s: e - line %d of \"%s\", no grammar has been \ +specified\n", myname, lineno, input_file_name); + done(1); +} + + +terminal_lhs(s_lineno) +int s_lineno; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", a token appears on the lhs \ +of a production\n", myname, s_lineno, input_file_name); + done(1); +} + + +prec_redeclared() +{ + fprintf(stderr, "%s: w - line %d of \"%s\", conflicting %%prec \ +specifiers\n", myname, lineno, input_file_name); +} + + +unterminated_action(a_lineno, a_line, a_cptr) +int a_lineno; +char *a_line; +char *a_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unterminated action\n", + myname, a_lineno, input_file_name); + print_pos(a_line, a_cptr); + done(1); +} + + +dollar_warning(a_lineno, i) +int a_lineno; +int i; +{ + fprintf(stderr, "%s: w - line %d of \"%s\", $%d references beyond the \ +end of the current rule\n", myname, a_lineno, input_file_name, i); +} + + +dollar_error(a_lineno, a_line, a_cptr) +int a_lineno; +char *a_line; +char *a_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", illegal $-name\n", + myname, a_lineno, input_file_name); + print_pos(a_line, a_cptr); + done(1); +} + + +untyped_lhs() +{ + fprintf(stderr, "%s: e - line %d of \"%s\", $$ is untyped\n", + myname, lineno, input_file_name); + done(1); +} + + +untyped_rhs(i, s) +int i; +char *s; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", $%d (%s) is untyped\n", + myname, lineno, input_file_name, i, s); + done(1); +} + + +unknown_rhs(i) +int i; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", $%d is untyped\n", + myname, lineno, input_file_name, i); + done(1); +} + + +default_action_warning() +{ + fprintf(stderr, "%s: w - line %d of \"%s\", the default action assigns an \ +undefined value to $$\n", myname, lineno, input_file_name); +} + + +undefined_goal(s) +char *s; +{ + fprintf(stderr, "%s: e - the start symbol %s is undefined\n", myname, s); + done(1); +} + + +undefined_symbol_warning(s) +char *s; +{ + fprintf(stderr, "%s: w - the symbol %s is undefined\n", myname, s); +} diff --git a/usr.bin/yacc/lalr.c b/usr.bin/yacc/lalr.c new file mode 100644 index 0000000..bf9aec8 --- /dev/null +++ b/usr.bin/yacc/lalr.c @@ -0,0 +1,678 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)lalr.c 5.3 (Berkeley) 6/1/90"; +#endif /* not lint */ + +#include "defs.h" + +typedef + struct shorts + { + struct shorts *next; + short value; + } + shorts; + +int tokensetsize; +short *lookaheads; +short *LAruleno; +unsigned *LA; +short *accessing_symbol; +core **state_table; +shifts **shift_table; +reductions **reduction_table; +short *goto_map; +short *from_state; +short *to_state; + +short **transpose(); + +static int infinity; +static int maxrhs; +static int ngotos; +static unsigned *F; +static short **includes; +static shorts **lookback; +static short **R; +static short *INDEX; +static short *VERTICES; +static int top; + + +lalr() +{ + tokensetsize = WORDSIZE(ntokens); + + set_state_table(); + set_accessing_symbol(); + set_shift_table(); + set_reduction_table(); + set_maxrhs(); + initialize_LA(); + set_goto_map(); + initialize_F(); + build_relations(); + compute_FOLLOWS(); + compute_lookaheads(); +} + + + +set_state_table() +{ + register core *sp; + + state_table = NEW2(nstates, core *); + for (sp = first_state; sp; sp = sp->next) + state_table[sp->number] = sp; +} + + + +set_accessing_symbol() +{ + register core *sp; + + accessing_symbol = NEW2(nstates, short); + for (sp = first_state; sp; sp = sp->next) + accessing_symbol[sp->number] = sp->accessing_symbol; +} + + + +set_shift_table() +{ + register shifts *sp; + + shift_table = NEW2(nstates, shifts *); + for (sp = first_shift; sp; sp = sp->next) + shift_table[sp->number] = sp; +} + + + +set_reduction_table() +{ + register reductions *rp; + + reduction_table = NEW2(nstates, reductions *); + for (rp = first_reduction; rp; rp = rp->next) + reduction_table[rp->number] = rp; +} + + + +set_maxrhs() +{ + register short *itemp; + register short *item_end; + register int length; + register int max; + + length = 0; + max = 0; + item_end = ritem + nitems; + for (itemp = ritem; itemp < item_end; itemp++) + { + if (*itemp >= 0) + { + length++; + } + else + { + if (length > max) max = length; + length = 0; + } + } + + maxrhs = max; +} + + + +initialize_LA() +{ + register int i, j, k; + register reductions *rp; + + lookaheads = NEW2(nstates + 1, short); + + k = 0; + for (i = 0; i < nstates; i++) + { + lookaheads[i] = k; + rp = reduction_table[i]; + if (rp) + k += rp->nreds; + } + lookaheads[nstates] = k; + + LA = NEW2(k * tokensetsize, unsigned); + LAruleno = NEW2(k, short); + lookback = NEW2(k, shorts *); + + k = 0; + for (i = 0; i < nstates; i++) + { + rp = reduction_table[i]; + if (rp) + { + for (j = 0; j < rp->nreds; j++) + { + LAruleno[k] = rp->rules[j]; + k++; + } + } + } +} + + +set_goto_map() +{ + register shifts *sp; + register int i; + register int symbol; + register int k; + register short *temp_map; + register int state2; + register int state1; + + goto_map = NEW2(nvars + 1, short) - ntokens; + temp_map = NEW2(nvars + 1, short) - ntokens; + + ngotos = 0; + for (sp = first_shift; sp; sp = sp->next) + { + for (i = sp->nshifts - 1; i >= 0; i--) + { + symbol = accessing_symbol[sp->shift[i]]; + + if (ISTOKEN(symbol)) break; + + if (ngotos == MAXSHORT) + fatal("too many gotos"); + + ngotos++; + goto_map[symbol]++; + } + } + + k = 0; + for (i = ntokens; i < nsyms; i++) + { + temp_map[i] = k; + k += goto_map[i]; + } + + for (i = ntokens; i < nsyms; i++) + goto_map[i] = temp_map[i]; + + goto_map[nsyms] = ngotos; + temp_map[nsyms] = ngotos; + + from_state = NEW2(ngotos, short); + to_state = NEW2(ngotos, short); + + for (sp = first_shift; sp; sp = sp->next) + { + state1 = sp->number; + for (i = sp->nshifts - 1; i >= 0; i--) + { + state2 = sp->shift[i]; + symbol = accessing_symbol[state2]; + + if (ISTOKEN(symbol)) break; + + k = temp_map[symbol]++; + from_state[k] = state1; + to_state[k] = state2; + } + } + + FREE(temp_map + ntokens); +} + + + +/* Map_goto maps a state/symbol pair into its numeric representation. */ + +int +map_goto(state, symbol) +int state; +int symbol; +{ + register int high; + register int low; + register int middle; + register int s; + + low = goto_map[symbol]; + high = goto_map[symbol + 1]; + + for (;;) + { + assert(low <= high); + middle = (low + high) >> 1; + s = from_state[middle]; + if (s == state) + return (middle); + else if (s < state) + low = middle + 1; + else + high = middle - 1; + } +} + + + +initialize_F() +{ + register int i; + register int j; + register int k; + register shifts *sp; + register short *edge; + register unsigned *rowp; + register short *rp; + register short **reads; + register int nedges; + register int stateno; + register int symbol; + register int nwords; + + nwords = ngotos * tokensetsize; + F = NEW2(nwords, unsigned); + + reads = NEW2(ngotos, short *); + edge = NEW2(ngotos + 1, short); + nedges = 0; + + rowp = F; + for (i = 0; i < ngotos; i++) + { + stateno = to_state[i]; + sp = shift_table[stateno]; + + if (sp) + { + k = sp->nshifts; + + for (j = 0; j < k; j++) + { + symbol = accessing_symbol[sp->shift[j]]; + if (ISVAR(symbol)) + break; + SETBIT(rowp, symbol); + } + + for (; j < k; j++) + { + symbol = accessing_symbol[sp->shift[j]]; + if (nullable[symbol]) + edge[nedges++] = map_goto(stateno, symbol); + } + + if (nedges) + { + reads[i] = rp = NEW2(nedges + 1, short); + + for (j = 0; j < nedges; j++) + rp[j] = edge[j]; + + rp[nedges] = -1; + nedges = 0; + } + } + + rowp += tokensetsize; + } + + SETBIT(F, 0); + digraph(reads); + + for (i = 0; i < ngotos; i++) + { + if (reads[i]) + FREE(reads[i]); + } + + FREE(reads); + FREE(edge); +} + + + +build_relations() +{ + register int i; + register int j; + register int k; + register short *rulep; + register short *rp; + register shifts *sp; + register int length; + register int nedges; + register int done; + register int state1; + register int stateno; + register int symbol1; + register int symbol2; + register short *shortp; + register short *edge; + register short *states; + register short **new_includes; + + includes = NEW2(ngotos, short *); + edge = NEW2(ngotos + 1, short); + states = NEW2(maxrhs + 1, short); + + for (i = 0; i < ngotos; i++) + { + nedges = 0; + state1 = from_state[i]; + symbol1 = accessing_symbol[to_state[i]]; + + for (rulep = derives[symbol1]; *rulep >= 0; rulep++) + { + length = 1; + states[0] = state1; + stateno = state1; + + for (rp = ritem + rrhs[*rulep]; *rp >= 0; rp++) + { + symbol2 = *rp; + sp = shift_table[stateno]; + k = sp->nshifts; + + for (j = 0; j < k; j++) + { + stateno = sp->shift[j]; + if (accessing_symbol[stateno] == symbol2) break; + } + + states[length++] = stateno; + } + + add_lookback_edge(stateno, *rulep, i); + + length--; + done = 0; + while (!done) + { + done = 1; + rp--; + if (ISVAR(*rp)) + { + stateno = states[--length]; + edge[nedges++] = map_goto(stateno, *rp); + if (nullable[*rp] && length > 0) done = 0; + } + } + } + + if (nedges) + { + includes[i] = shortp = NEW2(nedges + 1, short); + for (j = 0; j < nedges; j++) + shortp[j] = edge[j]; + shortp[nedges] = -1; + } + } + + new_includes = transpose(includes, ngotos); + + for (i = 0; i < ngotos; i++) + if (includes[i]) + FREE(includes[i]); + + FREE(includes); + + includes = new_includes; + + FREE(edge); + FREE(states); +} + + +add_lookback_edge(stateno, ruleno, gotono) +int stateno, ruleno, gotono; +{ + register int i, k; + register int found; + register shorts *sp; + + i = lookaheads[stateno]; + k = lookaheads[stateno + 1]; + found = 0; + while (!found && i < k) + { + if (LAruleno[i] == ruleno) + found = 1; + else + ++i; + } + assert(found); + + sp = NEW(shorts); + sp->next = lookback[i]; + sp->value = gotono; + lookback[i] = sp; +} + + + +short ** +transpose(R, n) +short **R; +int n; +{ + register short **new_R; + register short **temp_R; + register short *nedges; + register short *sp; + register int i; + register int k; + + nedges = NEW2(n, short); + + for (i = 0; i < n; i++) + { + sp = R[i]; + if (sp) + { + while (*sp >= 0) + nedges[*sp++]++; + } + } + + new_R = NEW2(n, short *); + temp_R = NEW2(n, short *); + + for (i = 0; i < n; i++) + { + k = nedges[i]; + if (k > 0) + { + sp = NEW2(k + 1, short); + new_R[i] = sp; + temp_R[i] = sp; + sp[k] = -1; + } + } + + FREE(nedges); + + for (i = 0; i < n; i++) + { + sp = R[i]; + if (sp) + { + while (*sp >= 0) + *temp_R[*sp++]++ = i; + } + } + + FREE(temp_R); + + return (new_R); +} + + + +compute_FOLLOWS() +{ + digraph(includes); +} + + +compute_lookaheads() +{ + register int i, n; + register unsigned *fp1, *fp2, *fp3; + register shorts *sp, *next; + register unsigned *rowp; + + rowp = LA; + n = lookaheads[nstates]; + for (i = 0; i < n; i++) + { + fp3 = rowp + tokensetsize; + for (sp = lookback[i]; sp; sp = sp->next) + { + fp1 = rowp; + fp2 = F + tokensetsize * sp->value; + while (fp1 < fp3) + *fp1++ |= *fp2++; + } + rowp = fp3; + } + + for (i = 0; i < n; i++) + for (sp = lookback[i]; sp; sp = next) + { + next = sp->next; + FREE(sp); + } + + FREE(lookback); + FREE(F); +} + + +digraph(relation) +short **relation; +{ + register int i; + + infinity = ngotos + 2; + INDEX = NEW2(ngotos + 1, short); + VERTICES = NEW2(ngotos + 1, short); + top = 0; + + R = relation; + + for (i = 0; i < ngotos; i++) + INDEX[i] = 0; + + for (i = 0; i < ngotos; i++) + { + if (INDEX[i] == 0 && R[i]) + traverse(i); + } + + FREE(INDEX); + FREE(VERTICES); +} + + + +traverse(i) +register int i; +{ + register unsigned *fp1; + register unsigned *fp2; + register unsigned *fp3; + register int j; + register short *rp; + + int height; + unsigned *base; + + VERTICES[++top] = i; + INDEX[i] = height = top; + + base = F + i * tokensetsize; + fp3 = base + tokensetsize; + + rp = R[i]; + if (rp) + { + while ((j = *rp++) >= 0) + { + if (INDEX[j] == 0) + traverse(j); + + if (INDEX[i] > INDEX[j]) + INDEX[i] = INDEX[j]; + + fp1 = base; + fp2 = F + j * tokensetsize; + + while (fp1 < fp3) + *fp1++ |= *fp2++; + } + } + + if (INDEX[i] == height) + { + for (;;) + { + j = VERTICES[top--]; + INDEX[j] = infinity; + + if (i == j) + break; + + fp1 = base; + fp2 = F + j * tokensetsize; + + while (fp1 < fp3) + *fp2++ = *fp1++; + } + } +} diff --git a/usr.bin/yacc/lr0.c b/usr.bin/yacc/lr0.c new file mode 100644 index 0000000..43106ea --- /dev/null +++ b/usr.bin/yacc/lr0.c @@ -0,0 +1,637 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)lr0.c 5.3 (Berkeley) 1/20/91"; +#endif /* not lint */ + +#include "defs.h" + +extern short *itemset; +extern short *itemsetend; +extern unsigned *ruleset; + +int nstates; +core *first_state; +shifts *first_shift; +reductions *first_reduction; + +int get_state(); +core *new_state(); + +static core **state_set; +static core *this_state; +static core *last_state; +static shifts *last_shift; +static reductions *last_reduction; + +static int nshifts; +static short *shift_symbol; + +static short *redset; +static short *shiftset; + +static short **kernel_base; +static short **kernel_end; +static short *kernel_items; + + +allocate_itemsets() +{ + register short *itemp; + register short *item_end; + register int symbol; + register int i; + register int count; + register int max; + register short *symbol_count; + + count = 0; + symbol_count = NEW2(nsyms, short); + + item_end = ritem + nitems; + for (itemp = ritem; itemp < item_end; itemp++) + { + symbol = *itemp; + if (symbol >= 0) + { + count++; + symbol_count[symbol]++; + } + } + + kernel_base = NEW2(nsyms, short *); + kernel_items = NEW2(count, short); + + count = 0; + max = 0; + for (i = 0; i < nsyms; i++) + { + kernel_base[i] = kernel_items + count; + count += symbol_count[i]; + if (max < symbol_count[i]) + max = symbol_count[i]; + } + + shift_symbol = symbol_count; + kernel_end = NEW2(nsyms, short *); +} + + +allocate_storage() +{ + allocate_itemsets(); + shiftset = NEW2(nsyms, short); + redset = NEW2(nrules + 1, short); + state_set = NEW2(nitems, core *); +} + + +append_states() +{ + register int i; + register int j; + register int symbol; + +#ifdef TRACE + fprintf(stderr, "Entering append_states()\n"); +#endif + for (i = 1; i < nshifts; i++) + { + symbol = shift_symbol[i]; + j = i; + while (j > 0 && shift_symbol[j - 1] > symbol) + { + shift_symbol[j] = shift_symbol[j - 1]; + j--; + } + shift_symbol[j] = symbol; + } + + for (i = 0; i < nshifts; i++) + { + symbol = shift_symbol[i]; + shiftset[i] = get_state(symbol); + } +} + + +free_storage() +{ + FREE(shift_symbol); + FREE(redset); + FREE(shiftset); + FREE(kernel_base); + FREE(kernel_end); + FREE(kernel_items); + FREE(state_set); +} + + + +generate_states() +{ + allocate_storage(); + itemset = NEW2(nitems, short); + ruleset = NEW2(WORDSIZE(nrules), unsigned); + set_first_derives(); + initialize_states(); + + while (this_state) + { + closure(this_state->items, this_state->nitems); + save_reductions(); + new_itemsets(); + append_states(); + + if (nshifts > 0) + save_shifts(); + + this_state = this_state->next; + } + + finalize_closure(); + free_storage(); +} + + + +int +get_state(symbol) +int symbol; +{ + register int key; + register short *isp1; + register short *isp2; + register short *iend; + register core *sp; + register int found; + register int n; + +#ifdef TRACE + fprintf(stderr, "Entering get_state(%d)\n", symbol); +#endif + + isp1 = kernel_base[symbol]; + iend = kernel_end[symbol]; + n = iend - isp1; + + key = *isp1; + assert(0 <= key && key < nitems); + sp = state_set[key]; + if (sp) + { + found = 0; + while (!found) + { + if (sp->nitems == n) + { + found = 1; + isp1 = kernel_base[symbol]; + isp2 = sp->items; + + while (found && isp1 < iend) + { + if (*isp1++ != *isp2++) + found = 0; + } + } + + if (!found) + { + if (sp->link) + { + sp = sp->link; + } + else + { + sp = sp->link = new_state(symbol); + found = 1; + } + } + } + } + else + { + state_set[key] = sp = new_state(symbol); + } + + return (sp->number); +} + + + +initialize_states() +{ + register int i; + register short *start_derives; + register core *p; + + start_derives = derives[start_symbol]; + for (i = 0; start_derives[i] >= 0; ++i) + continue; + + p = (core *) MALLOC(sizeof(core) + i*sizeof(short)); + if (p == 0) no_space(); + + p->next = 0; + p->link = 0; + p->number = 0; + p->accessing_symbol = 0; + p->nitems = i; + + for (i = 0; start_derives[i] >= 0; ++i) + p->items[i] = rrhs[start_derives[i]]; + + first_state = last_state = this_state = p; + nstates = 1; +} + + +new_itemsets() +{ + register int i; + register int shiftcount; + register short *isp; + register short *ksp; + register int symbol; + + for (i = 0; i < nsyms; i++) + kernel_end[i] = 0; + + shiftcount = 0; + isp = itemset; + while (isp < itemsetend) + { + i = *isp++; + symbol = ritem[i]; + if (symbol > 0) + { + ksp = kernel_end[symbol]; + if (!ksp) + { + shift_symbol[shiftcount++] = symbol; + ksp = kernel_base[symbol]; + } + + *ksp++ = i + 1; + kernel_end[symbol] = ksp; + } + } + + nshifts = shiftcount; +} + + + +core * +new_state(symbol) +int symbol; +{ + register int n; + register core *p; + register short *isp1; + register short *isp2; + register short *iend; + +#ifdef TRACE + fprintf(stderr, "Entering new_state(%d)\n", symbol); +#endif + + if (nstates >= MAXSHORT) + fatal("too many states"); + + isp1 = kernel_base[symbol]; + iend = kernel_end[symbol]; + n = iend - isp1; + + p = (core *) allocate((unsigned) (sizeof(core) + (n - 1) * sizeof(short))); + p->accessing_symbol = symbol; + p->number = nstates; + p->nitems = n; + + isp2 = p->items; + while (isp1 < iend) + *isp2++ = *isp1++; + + last_state->next = p; + last_state = p; + + nstates++; + + return (p); +} + + +/* show_cores is used for debugging */ + +show_cores() +{ + core *p; + int i, j, k, n; + int itemno; + + k = 0; + for (p = first_state; p; ++k, p = p->next) + { + if (k) printf("\n"); + printf("state %d, number = %d, accessing symbol = %s\n", + k, p->number, symbol_name[p->accessing_symbol]); + n = p->nitems; + for (i = 0; i < n; ++i) + { + itemno = p->items[i]; + printf("%4d ", itemno); + j = itemno; + while (ritem[j] >= 0) ++j; + printf("%s :", symbol_name[rlhs[-ritem[j]]]); + j = rrhs[-ritem[j]]; + while (j < itemno) + printf(" %s", symbol_name[ritem[j++]]); + printf(" ."); + while (ritem[j] >= 0) + printf(" %s", symbol_name[ritem[j++]]); + printf("\n"); + fflush(stdout); + } + } +} + + +/* show_ritems is used for debugging */ + +show_ritems() +{ + int i; + + for (i = 0; i < nitems; ++i) + printf("ritem[%d] = %d\n", i, ritem[i]); +} + + +/* show_rrhs is used for debugging */ +show_rrhs() +{ + int i; + + for (i = 0; i < nrules; ++i) + printf("rrhs[%d] = %d\n", i, rrhs[i]); +} + + +/* show_shifts is used for debugging */ + +show_shifts() +{ + shifts *p; + int i, j, k; + + k = 0; + for (p = first_shift; p; ++k, p = p->next) + { + if (k) printf("\n"); + printf("shift %d, number = %d, nshifts = %d\n", k, p->number, + p->nshifts); + j = p->nshifts; + for (i = 0; i < j; ++i) + printf("\t%d\n", p->shift[i]); + } +} + + +save_shifts() +{ + register shifts *p; + register short *sp1; + register short *sp2; + register short *send; + + p = (shifts *) allocate((unsigned) (sizeof(shifts) + + (nshifts - 1) * sizeof(short))); + + p->number = this_state->number; + p->nshifts = nshifts; + + sp1 = shiftset; + sp2 = p->shift; + send = shiftset + nshifts; + + while (sp1 < send) + *sp2++ = *sp1++; + + if (last_shift) + { + last_shift->next = p; + last_shift = p; + } + else + { + first_shift = p; + last_shift = p; + } +} + + + +save_reductions() +{ + register short *isp; + register short *rp1; + register short *rp2; + register int item; + register int count; + register reductions *p; + register short *rend; + + count = 0; + for (isp = itemset; isp < itemsetend; isp++) + { + item = ritem[*isp]; + if (item < 0) + { + redset[count++] = -item; + } + } + + if (count) + { + p = (reductions *) allocate((unsigned) (sizeof(reductions) + + (count - 1) * sizeof(short))); + + p->number = this_state->number; + p->nreds = count; + + rp1 = redset; + rp2 = p->rules; + rend = rp1 + count; + + while (rp1 < rend) + *rp2++ = *rp1++; + + if (last_reduction) + { + last_reduction->next = p; + last_reduction = p; + } + else + { + first_reduction = p; + last_reduction = p; + } + } +} + + +set_derives() +{ + register int i, k; + register int lhs; + register short *rules; + + derives = NEW2(nsyms, short *); + rules = NEW2(nvars + nrules, short); + + k = 0; + for (lhs = start_symbol; lhs < nsyms; lhs++) + { + derives[lhs] = rules + k; + for (i = 0; i < nrules; i++) + { + if (rlhs[i] == lhs) + { + rules[k] = i; + k++; + } + } + rules[k] = -1; + k++; + } + +#ifdef DEBUG + print_derives(); +#endif +} + +free_derives() +{ + FREE(derives[start_symbol]); + FREE(derives); +} + +#ifdef DEBUG +print_derives() +{ + register int i; + register short *sp; + + printf("\nDERIVES\n\n"); + + for (i = start_symbol; i < nsyms; i++) + { + printf("%s derives ", symbol_name[i]); + for (sp = derives[i]; *sp >= 0; sp++) + { + printf(" %d", *sp); + } + putchar('\n'); + } + + putchar('\n'); +} +#endif + + +set_nullable() +{ + register int i, j; + register int empty; + int done; + + nullable = MALLOC(nsyms); + if (nullable == 0) no_space(); + + for (i = 0; i < nsyms; ++i) + nullable[i] = 0; + + done = 0; + while (!done) + { + done = 1; + for (i = 1; i < nitems; i++) + { + empty = 1; + while ((j = ritem[i]) >= 0) + { + if (!nullable[j]) + empty = 0; + ++i; + } + if (empty) + { + j = rlhs[-j]; + if (!nullable[j]) + { + nullable[j] = 1; + done = 0; + } + } + } + } + +#ifdef DEBUG + for (i = 0; i < nsyms; i++) + { + if (nullable[i]) + printf("%s is nullable\n", symbol_name[i]); + else + printf("%s is not nullable\n", symbol_name[i]); + } +#endif +} + + +free_nullable() +{ + FREE(nullable); +} + + +lr0() +{ + set_derives(); + set_nullable(); + generate_states(); +} diff --git a/usr.bin/yacc/main.c b/usr.bin/yacc/main.c new file mode 100644 index 0000000..79b332a --- /dev/null +++ b/usr.bin/yacc/main.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 5.5 (Berkeley) 5/24/93"; +#endif /* not lint */ + +#include <signal.h> +#include "defs.h" + +char dflag; +char lflag; +char rflag; +char tflag; +char vflag; + +char *symbol_prefix; +char *file_prefix = "y"; +char *myname = "yacc"; +char *temp_form = "yacc.XXXXXXX"; + +int lineno; +int outline; + +char *action_file_name; +char *code_file_name; +char *defines_file_name; +char *input_file_name = ""; +char *output_file_name; +char *text_file_name; +char *union_file_name; +char *verbose_file_name; + +FILE *action_file; /* a temp file, used to save actions associated */ + /* with rules until the parser is written */ +FILE *code_file; /* y.code.c (used when the -r option is specified) */ +FILE *defines_file; /* y.tab.h */ +FILE *input_file; /* the input file */ +FILE *output_file; /* y.tab.c */ +FILE *text_file; /* a temp file, used to save text until all */ + /* symbols have been defined */ +FILE *union_file; /* a temp file, used to save the union */ + /* definition until all symbol have been */ + /* defined */ +FILE *verbose_file; /* y.output */ + +int nitems; +int nrules; +int nsyms; +int ntokens; +int nvars; + +int start_symbol; +char **symbol_name; +short *symbol_value; +short *symbol_prec; +char *symbol_assoc; + +short *ritem; +short *rlhs; +short *rrhs; +short *rprec; +char *rassoc; +short **derives; +char *nullable; + +extern char *mktemp(); +extern char *getenv(); + + +done(k) +int k; +{ + if (action_file) { fclose(action_file); unlink(action_file_name); } + if (text_file) { fclose(text_file); unlink(text_file_name); } + if (union_file) { fclose(union_file); unlink(union_file_name); } + exit(k); +} + + +void +onintr(signo) + int signo; +{ + done(1); +} + + +set_signals() +{ +#ifdef SIGINT + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, onintr); +#endif +#ifdef SIGTERM + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) + signal(SIGTERM, onintr); +#endif +#ifdef SIGHUP + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + signal(SIGHUP, onintr); +#endif +} + + +usage() +{ + fprintf(stderr, "usage: %s [-dlrtv] [-b file_prefix] [-p symbol_prefix] filename\n", myname); + exit(1); +} + + +getargs(argc, argv) +int argc; +char *argv[]; +{ + register int i; + register char *s; + + if (argc > 0) myname = argv[0]; + for (i = 1; i < argc; ++i) + { + s = argv[i]; + if (*s != '-') break; + switch (*++s) + { + case '\0': + input_file = stdin; + if (i + 1 < argc) usage(); + return; + + case '-': + ++i; + goto no_more_options; + + case 'b': + if (*++s) + file_prefix = s; + else if (++i < argc) + file_prefix = argv[i]; + else + usage(); + continue; + + case 'd': + dflag = 1; + break; + + case 'l': + lflag = 1; + break; + + case 'p': + if (*++s) + symbol_prefix = s; + else if (++i < argc) + symbol_prefix = argv[i]; + else + usage(); + continue; + + case 'r': + rflag = 1; + break; + + case 't': + tflag = 1; + break; + + case 'v': + vflag = 1; + break; + + default: + usage(); + } + + for (;;) + { + switch (*++s) + { + case '\0': + goto end_of_option; + + case 'd': + dflag = 1; + break; + + case 'l': + lflag = 1; + break; + + case 'r': + rflag = 1; + break; + + case 't': + tflag = 1; + break; + + case 'v': + vflag = 1; + break; + + default: + usage(); + } + } +end_of_option:; + } + +no_more_options:; + if (i + 1 != argc) usage(); + input_file_name = argv[i]; +} + + +char * +allocate(n) +unsigned n; +{ + register char *p; + + p = NULL; + if (n) + { + p = CALLOC(1, n); + if (!p) no_space(); + } + return (p); +} + + +create_file_names() +{ + int i, len; + char *tmpdir; + + tmpdir = getenv("TMPDIR"); + if (tmpdir == 0) tmpdir = "/tmp"; + + len = strlen(tmpdir); + i = len + 13; + if (len && tmpdir[len-1] != '/') + ++i; + + action_file_name = MALLOC(i); + if (action_file_name == 0) no_space(); + text_file_name = MALLOC(i); + if (text_file_name == 0) no_space(); + union_file_name = MALLOC(i); + if (union_file_name == 0) no_space(); + + strcpy(action_file_name, tmpdir); + strcpy(text_file_name, tmpdir); + strcpy(union_file_name, tmpdir); + + if (len && tmpdir[len - 1] != '/') + { + action_file_name[len] = '/'; + text_file_name[len] = '/'; + union_file_name[len] = '/'; + ++len; + } + + strcpy(action_file_name + len, temp_form); + strcpy(text_file_name + len, temp_form); + strcpy(union_file_name + len, temp_form); + + action_file_name[len + 5] = 'a'; + text_file_name[len + 5] = 't'; + union_file_name[len + 5] = 'u'; + + mktemp(action_file_name); + mktemp(text_file_name); + mktemp(union_file_name); + + len = strlen(file_prefix); + + output_file_name = MALLOC(len + 7); + if (output_file_name == 0) + no_space(); + strcpy(output_file_name, file_prefix); + strcpy(output_file_name + len, OUTPUT_SUFFIX); + + if (rflag) + { + code_file_name = MALLOC(len + 8); + if (code_file_name == 0) + no_space(); + strcpy(code_file_name, file_prefix); + strcpy(code_file_name + len, CODE_SUFFIX); + } + else + code_file_name = output_file_name; + + if (dflag) + { + defines_file_name = MALLOC(len + 7); + if (defines_file_name == 0) + no_space(); + strcpy(defines_file_name, file_prefix); + strcpy(defines_file_name + len, DEFINES_SUFFIX); + } + + if (vflag) + { + verbose_file_name = MALLOC(len + 8); + if (verbose_file_name == 0) + no_space(); + strcpy(verbose_file_name, file_prefix); + strcpy(verbose_file_name + len, VERBOSE_SUFFIX); + } +} + + +open_files() +{ + create_file_names(); + + if (input_file == 0) + { + input_file = fopen(input_file_name, "r"); + if (input_file == 0) + open_error(input_file_name); + } + + action_file = fopen(action_file_name, "w"); + if (action_file == 0) + open_error(action_file_name); + + text_file = fopen(text_file_name, "w"); + if (text_file == 0) + open_error(text_file_name); + + if (vflag) + { + verbose_file = fopen(verbose_file_name, "w"); + if (verbose_file == 0) + open_error(verbose_file_name); + } + + if (dflag) + { + defines_file = fopen(defines_file_name, "w"); + if (defines_file == 0) + open_error(defines_file_name); + union_file = fopen(union_file_name, "w"); + if (union_file == 0) + open_error(union_file_name); + } + + output_file = fopen(output_file_name, "w"); + if (output_file == 0) + open_error(output_file_name); + + if (rflag) + { + code_file = fopen(code_file_name, "w"); + if (code_file == 0) + open_error(code_file_name); + } + else + code_file = output_file; +} + + +int +main(argc, argv) +int argc; +char *argv[]; +{ + set_signals(); + getargs(argc, argv); + open_files(); + reader(); + lr0(); + lalr(); + make_parser(); + verbose(); + output(); + done(0); + /*NOTREACHED*/ +} diff --git a/usr.bin/yacc/mkpar.c b/usr.bin/yacc/mkpar.c new file mode 100644 index 0000000..42ead14 --- /dev/null +++ b/usr.bin/yacc/mkpar.c @@ -0,0 +1,395 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)mkpar.c 5.3 (Berkeley) 1/20/91"; +#endif /* not lint */ + +#include "defs.h" + +action **parser; +int SRtotal; +int RRtotal; +short *SRconflicts; +short *RRconflicts; +short *defred; +short *rules_used; +short nunused; +short final_state; + +static int SRcount; +static int RRcount; + +extern action *parse_actions(); +extern action *get_shifts(); +extern action *add_reductions(); +extern action *add_reduce(); + + +make_parser() +{ + register int i; + + parser = NEW2(nstates, action *); + for (i = 0; i < nstates; i++) + parser[i] = parse_actions(i); + + find_final_state(); + remove_conflicts(); + unused_rules(); + if (SRtotal + RRtotal > 0) total_conflicts(); + defreds(); +} + + +action * +parse_actions(stateno) +register int stateno; +{ + register action *actions; + + actions = get_shifts(stateno); + actions = add_reductions(stateno, actions); + return (actions); +} + + +action * +get_shifts(stateno) +int stateno; +{ + register action *actions, *temp; + register shifts *sp; + register short *to_state; + register int i, k; + register int symbol; + + actions = 0; + sp = shift_table[stateno]; + if (sp) + { + to_state = sp->shift; + for (i = sp->nshifts - 1; i >= 0; i--) + { + k = to_state[i]; + symbol = accessing_symbol[k]; + if (ISTOKEN(symbol)) + { + temp = NEW(action); + temp->next = actions; + temp->symbol = symbol; + temp->number = k; + temp->prec = symbol_prec[symbol]; + temp->action_code = SHIFT; + temp->assoc = symbol_assoc[symbol]; + actions = temp; + } + } + } + return (actions); +} + +action * +add_reductions(stateno, actions) +int stateno; +register action *actions; +{ + register int i, j, m, n; + register int ruleno, tokensetsize; + register unsigned *rowp; + + tokensetsize = WORDSIZE(ntokens); + m = lookaheads[stateno]; + n = lookaheads[stateno + 1]; + for (i = m; i < n; i++) + { + ruleno = LAruleno[i]; + rowp = LA + i * tokensetsize; + for (j = ntokens - 1; j >= 0; j--) + { + if (BIT(rowp, j)) + actions = add_reduce(actions, ruleno, j); + } + } + return (actions); +} + + +action * +add_reduce(actions, ruleno, symbol) +register action *actions; +register int ruleno, symbol; +{ + register action *temp, *prev, *next; + + prev = 0; + for (next = actions; next && next->symbol < symbol; next = next->next) + prev = next; + + while (next && next->symbol == symbol && next->action_code == SHIFT) + { + prev = next; + next = next->next; + } + + while (next && next->symbol == symbol && + next->action_code == REDUCE && next->number < ruleno) + { + prev = next; + next = next->next; + } + + temp = NEW(action); + temp->next = next; + temp->symbol = symbol; + temp->number = ruleno; + temp->prec = rprec[ruleno]; + temp->action_code = REDUCE; + temp->assoc = rassoc[ruleno]; + + if (prev) + prev->next = temp; + else + actions = temp; + + return (actions); +} + + +find_final_state() +{ + register int goal, i; + register short *to_state; + register shifts *p; + + p = shift_table[0]; + to_state = p->shift; + goal = ritem[1]; + for (i = p->nshifts - 1; i >= 0; --i) + { + final_state = to_state[i]; + if (accessing_symbol[final_state] == goal) break; + } +} + + +unused_rules() +{ + register int i; + register action *p; + + rules_used = (short *) MALLOC(nrules*sizeof(short)); + if (rules_used == 0) no_space(); + + for (i = 0; i < nrules; ++i) + rules_used[i] = 0; + + for (i = 0; i < nstates; ++i) + { + for (p = parser[i]; p; p = p->next) + { + if (p->action_code == REDUCE && p->suppressed == 0) + rules_used[p->number] = 1; + } + } + + nunused = 0; + for (i = 3; i < nrules; ++i) + if (!rules_used[i]) ++nunused; + + if (nunused) + if (nunused == 1) + fprintf(stderr, "%s: 1 rule never reduced\n", myname); + else + fprintf(stderr, "%s: %d rules never reduced\n", myname, nunused); +} + + +remove_conflicts() +{ + register int i; + register int symbol; + register action *p, *pref; + + SRtotal = 0; + RRtotal = 0; + SRconflicts = NEW2(nstates, short); + RRconflicts = NEW2(nstates, short); + for (i = 0; i < nstates; i++) + { + SRcount = 0; + RRcount = 0; + symbol = -1; + for (p = parser[i]; p; p = p->next) + { + if (p->symbol != symbol) + { + pref = p; + symbol = p->symbol; + } + else if (i == final_state && symbol == 0) + { + SRcount++; + p->suppressed = 1; + } + else if (pref->action_code == SHIFT) + { + if (pref->prec > 0 && p->prec > 0) + { + if (pref->prec < p->prec) + { + pref->suppressed = 2; + pref = p; + } + else if (pref->prec > p->prec) + { + p->suppressed = 2; + } + else if (pref->assoc == LEFT) + { + pref->suppressed = 2; + pref = p; + } + else if (pref->assoc == RIGHT) + { + p->suppressed = 2; + } + else + { + pref->suppressed = 2; + p->suppressed = 2; + } + } + else + { + SRcount++; + p->suppressed = 1; + } + } + else + { + RRcount++; + p->suppressed = 1; + } + } + SRtotal += SRcount; + RRtotal += RRcount; + SRconflicts[i] = SRcount; + RRconflicts[i] = RRcount; + } +} + + +total_conflicts() +{ + fprintf(stderr, "%s: ", myname); + if (SRtotal == 1) + fprintf(stderr, "1 shift/reduce conflict"); + else if (SRtotal > 1) + fprintf(stderr, "%d shift/reduce conflicts", SRtotal); + + if (SRtotal && RRtotal) + fprintf(stderr, ", "); + + if (RRtotal == 1) + fprintf(stderr, "1 reduce/reduce conflict"); + else if (RRtotal > 1) + fprintf(stderr, "%d reduce/reduce conflicts", RRtotal); + + fprintf(stderr, ".\n"); +} + + +int +sole_reduction(stateno) +int stateno; +{ + register int count, ruleno; + register action *p; + + count = 0; + ruleno = 0; + for (p = parser[stateno]; p; p = p->next) + { + if (p->action_code == SHIFT && p->suppressed == 0) + return (0); + else if (p->action_code == REDUCE && p->suppressed == 0) + { + if (ruleno > 0 && p->number != ruleno) + return (0); + if (p->symbol != 1) + ++count; + ruleno = p->number; + } + } + + if (count == 0) + return (0); + return (ruleno); +} + + +defreds() +{ + register int i; + + defred = NEW2(nstates, short); + for (i = 0; i < nstates; i++) + defred[i] = sole_reduction(i); +} + +free_action_row(p) +register action *p; +{ + register action *q; + + while (p) + { + q = p->next; + FREE(p); + p = q; + } +} + +free_parser() +{ + register int i; + + for (i = 0; i < nstates; i++) + free_action_row(parser[i]); + + FREE(parser); +} diff --git a/usr.bin/yacc/output.c b/usr.bin/yacc/output.c new file mode 100644 index 0000000..f8fd1c5 --- /dev/null +++ b/usr.bin/yacc/output.c @@ -0,0 +1,1250 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)output.c 5.7 (Berkeley) 5/24/93"; +#endif /* not lint */ + +#include "defs.h" + +static int nvectors; +static int nentries; +static short **froms; +static short **tos; +static short *tally; +static short *width; +static short *state_count; +static short *order; +static short *base; +static short *pos; +static int maxtable; +static short *table; +static short *check; +static int lowzero; +static int high; + + +output() +{ + free_itemsets(); + free_shifts(); + free_reductions(); + output_prefix(); + output_stored_text(); + output_defines(); + output_rule_data(); + output_yydefred(); + output_actions(); + free_parser(); + output_debug(); + output_stype(); + if (rflag) write_section(tables); + write_section(header); + output_trailing_text(); + write_section(body); + output_semantic_actions(); + write_section(trailer); +} + + +output_prefix() +{ + if (symbol_prefix == NULL) + symbol_prefix = "yy"; + else + { + ++outline; + fprintf(code_file, "#define yyparse %sparse\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yylex %slex\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyerror %serror\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yychar %schar\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyval %sval\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yylval %slval\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yydebug %sdebug\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yynerrs %snerrs\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyerrflag %serrflag\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyss %sss\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyssp %sssp\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyvs %svs\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyvsp %svsp\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yylhs %slhs\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yylen %slen\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yydefred %sdefred\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yydgoto %sdgoto\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yysindex %ssindex\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyrindex %srindex\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yygindex %sgindex\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yytable %stable\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yycheck %scheck\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyname %sname\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyrule %srule\n", symbol_prefix); + } + ++outline; + fprintf(code_file, "#define YYPREFIX \"%s\"\n", symbol_prefix); +} + + +output_rule_data() +{ + register int i; + register int j; + + + fprintf(output_file, "short %slhs[] = {%42d,", symbol_prefix, + symbol_value[start_symbol]); + + j = 10; + for (i = 3; i < nrules; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", symbol_value[rlhs[i]]); + } + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + + fprintf(output_file, "short %slen[] = {%42d,", symbol_prefix, 2); + + j = 10; + for (i = 3; i < nrules; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + j++; + + fprintf(output_file, "%5d,", rrhs[i + 1] - rrhs[i] - 1); + } + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); +} + + +output_yydefred() +{ + register int i, j; + + fprintf(output_file, "short %sdefred[] = {%39d,", symbol_prefix, + (defred[0] ? defred[0] - 2 : 0)); + + j = 10; + for (i = 1; i < nstates; i++) + { + if (j < 10) + ++j; + else + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + + fprintf(output_file, "%5d,", (defred[i] ? defred[i] - 2 : 0)); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); +} + + +output_actions() +{ + nvectors = 2*nstates + nvars; + + froms = NEW2(nvectors, short *); + tos = NEW2(nvectors, short *); + tally = NEW2(nvectors, short); + width = NEW2(nvectors, short); + + token_actions(); + FREE(lookaheads); + FREE(LA); + FREE(LAruleno); + FREE(accessing_symbol); + + goto_actions(); + FREE(goto_map + ntokens); + FREE(from_state); + FREE(to_state); + + sort_actions(); + pack_table(); + output_base(); + output_table(); + output_check(); +} + + +token_actions() +{ + register int i, j; + register int shiftcount, reducecount; + register int max, min; + register short *actionrow, *r, *s; + register action *p; + + actionrow = NEW2(2*ntokens, short); + for (i = 0; i < nstates; ++i) + { + if (parser[i]) + { + for (j = 0; j < 2*ntokens; ++j) + actionrow[j] = 0; + + shiftcount = 0; + reducecount = 0; + for (p = parser[i]; p; p = p->next) + { + if (p->suppressed == 0) + { + if (p->action_code == SHIFT) + { + ++shiftcount; + actionrow[p->symbol] = p->number; + } + else if (p->action_code == REDUCE && p->number != defred[i]) + { + ++reducecount; + actionrow[p->symbol + ntokens] = p->number; + } + } + } + + tally[i] = shiftcount; + tally[nstates+i] = reducecount; + width[i] = 0; + width[nstates+i] = 0; + if (shiftcount > 0) + { + froms[i] = r = NEW2(shiftcount, short); + tos[i] = s = NEW2(shiftcount, short); + min = MAXSHORT; + max = 0; + for (j = 0; j < ntokens; ++j) + { + if (actionrow[j]) + { + if (min > symbol_value[j]) + min = symbol_value[j]; + if (max < symbol_value[j]) + max = symbol_value[j]; + *r++ = symbol_value[j]; + *s++ = actionrow[j]; + } + } + width[i] = max - min + 1; + } + if (reducecount > 0) + { + froms[nstates+i] = r = NEW2(reducecount, short); + tos[nstates+i] = s = NEW2(reducecount, short); + min = MAXSHORT; + max = 0; + for (j = 0; j < ntokens; ++j) + { + if (actionrow[ntokens+j]) + { + if (min > symbol_value[j]) + min = symbol_value[j]; + if (max < symbol_value[j]) + max = symbol_value[j]; + *r++ = symbol_value[j]; + *s++ = actionrow[ntokens+j] - 2; + } + } + width[nstates+i] = max - min + 1; + } + } + } + FREE(actionrow); +} + +goto_actions() +{ + register int i, j, k; + + state_count = NEW2(nstates, short); + + k = default_goto(start_symbol + 1); + fprintf(output_file, "short %sdgoto[] = {%40d,", symbol_prefix, k); + save_column(start_symbol + 1, k); + + j = 10; + for (i = start_symbol + 2; i < nsyms; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + k = default_goto(i); + fprintf(output_file, "%5d,", k); + save_column(i, k); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + FREE(state_count); +} + +int +default_goto(symbol) +int symbol; +{ + register int i; + register int m; + register int n; + register int default_state; + register int max; + + m = goto_map[symbol]; + n = goto_map[symbol + 1]; + + if (m == n) return (0); + + for (i = 0; i < nstates; i++) + state_count[i] = 0; + + for (i = m; i < n; i++) + state_count[to_state[i]]++; + + max = 0; + default_state = 0; + for (i = 0; i < nstates; i++) + { + if (state_count[i] > max) + { + max = state_count[i]; + default_state = i; + } + } + + return (default_state); +} + + + +save_column(symbol, default_state) +int symbol; +int default_state; +{ + register int i; + register int m; + register int n; + register short *sp; + register short *sp1; + register short *sp2; + register int count; + register int symno; + + m = goto_map[symbol]; + n = goto_map[symbol + 1]; + + count = 0; + for (i = m; i < n; i++) + { + if (to_state[i] != default_state) + ++count; + } + if (count == 0) return; + + symno = symbol_value[symbol] + 2*nstates; + + froms[symno] = sp1 = sp = NEW2(count, short); + tos[symno] = sp2 = NEW2(count, short); + + for (i = m; i < n; i++) + { + if (to_state[i] != default_state) + { + *sp1++ = from_state[i]; + *sp2++ = to_state[i]; + } + } + + tally[symno] = count; + width[symno] = sp1[-1] - sp[0] + 1; +} + +sort_actions() +{ + register int i; + register int j; + register int k; + register int t; + register int w; + + order = NEW2(nvectors, short); + nentries = 0; + + for (i = 0; i < nvectors; i++) + { + if (tally[i] > 0) + { + t = tally[i]; + w = width[i]; + j = nentries - 1; + + while (j >= 0 && (width[order[j]] < w)) + j--; + + while (j >= 0 && (width[order[j]] == w) && (tally[order[j]] < t)) + j--; + + for (k = nentries - 1; k > j; k--) + order[k + 1] = order[k]; + + order[j + 1] = i; + nentries++; + } + } +} + + +pack_table() +{ + register int i; + register int place; + register int state; + + base = NEW2(nvectors, short); + pos = NEW2(nentries, short); + + maxtable = 1000; + table = NEW2(maxtable, short); + check = NEW2(maxtable, short); + + lowzero = 0; + high = 0; + + for (i = 0; i < maxtable; i++) + check[i] = -1; + + for (i = 0; i < nentries; i++) + { + state = matching_vector(i); + + if (state < 0) + place = pack_vector(i); + else + place = base[state]; + + pos[i] = place; + base[order[i]] = place; + } + + for (i = 0; i < nvectors; i++) + { + if (froms[i]) + FREE(froms[i]); + if (tos[i]) + FREE(tos[i]); + } + + FREE(froms); + FREE(tos); + FREE(pos); +} + + +/* The function matching_vector determines if the vector specified by */ +/* the input parameter matches a previously considered vector. The */ +/* test at the start of the function checks if the vector represents */ +/* a row of shifts over terminal symbols or a row of reductions, or a */ +/* column of shifts over a nonterminal symbol. Berkeley Yacc does not */ +/* check if a column of shifts over a nonterminal symbols matches a */ +/* previously considered vector. Because of the nature of LR parsing */ +/* tables, no two columns can match. Therefore, the only possible */ +/* match would be between a row and a column. Such matches are */ +/* unlikely. Therefore, to save time, no attempt is made to see if a */ +/* column matches a previously considered vector. */ +/* */ +/* Matching_vector is poorly designed. The test could easily be made */ +/* faster. Also, it depends on the vectors being in a specific */ +/* order. */ + +int +matching_vector(vector) +int vector; +{ + register int i; + register int j; + register int k; + register int t; + register int w; + register int match; + register int prev; + + i = order[vector]; + if (i >= 2*nstates) + return (-1); + + t = tally[i]; + w = width[i]; + + for (prev = vector - 1; prev >= 0; prev--) + { + j = order[prev]; + if (width[j] != w || tally[j] != t) + return (-1); + + match = 1; + for (k = 0; match && k < t; k++) + { + if (tos[j][k] != tos[i][k] || froms[j][k] != froms[i][k]) + match = 0; + } + + if (match) + return (j); + } + + return (-1); +} + + + +int +pack_vector(vector) +int vector; +{ + register int i, j, k, l; + register int t; + register int loc; + register int ok; + register short *from; + register short *to; + int newmax; + + i = order[vector]; + t = tally[i]; + assert(t); + + from = froms[i]; + to = tos[i]; + + j = lowzero - from[0]; + for (k = 1; k < t; ++k) + if (lowzero - from[k] > j) + j = lowzero - from[k]; + for (;; ++j) + { + if (j == 0) + continue; + ok = 1; + for (k = 0; ok && k < t; k++) + { + loc = j + from[k]; + if (loc >= maxtable) + { + if (loc >= MAXTABLE) + fatal("maximum table size exceeded"); + + newmax = maxtable; + do { newmax += 200; } while (newmax <= loc); + table = (short *) REALLOC(table, newmax*sizeof(short)); + if (table == 0) no_space(); + check = (short *) REALLOC(check, newmax*sizeof(short)); + if (check == 0) no_space(); + for (l = maxtable; l < newmax; ++l) + { + table[l] = 0; + check[l] = -1; + } + maxtable = newmax; + } + + if (check[loc] != -1) + ok = 0; + } + for (k = 0; ok && k < vector; k++) + { + if (pos[k] == j) + ok = 0; + } + if (ok) + { + for (k = 0; k < t; k++) + { + loc = j + from[k]; + table[loc] = to[k]; + check[loc] = from[k]; + if (loc > high) high = loc; + } + + while (check[lowzero] != -1) + ++lowzero; + + return (j); + } + } +} + + + +output_base() +{ + register int i, j; + + fprintf(output_file, "short %ssindex[] = {%39d,", symbol_prefix, base[0]); + + j = 10; + for (i = 1; i < nstates; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", base[i]); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\nshort %srindex[] = {%39d,", symbol_prefix, + base[nstates]); + + j = 10; + for (i = nstates + 1; i < 2*nstates; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", base[i]); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\nshort %sgindex[] = {%39d,", symbol_prefix, + base[2*nstates]); + + j = 10; + for (i = 2*nstates + 1; i < nvectors - 1; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", base[i]); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + FREE(base); +} + + + +output_table() +{ + register int i; + register int j; + + ++outline; + fprintf(code_file, "#define YYTABLESIZE %d\n", high); + fprintf(output_file, "short %stable[] = {%40d,", symbol_prefix, + table[0]); + + j = 10; + for (i = 1; i <= high; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", table[i]); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + FREE(table); +} + + + +output_check() +{ + register int i; + register int j; + + fprintf(output_file, "short %scheck[] = {%40d,", symbol_prefix, + check[0]); + + j = 10; + for (i = 1; i <= high; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", check[i]); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + FREE(check); +} + + +int +is_C_identifier(name) +char *name; +{ + register char *s; + register int c; + + s = name; + c = *s; + if (c == '"') + { + c = *++s; + if (!isalpha(c) && c != '_' && c != '$') + return (0); + while ((c = *++s) != '"') + { + if (!isalnum(c) && c != '_' && c != '$') + return (0); + } + return (1); + } + + if (!isalpha(c) && c != '_' && c != '$') + return (0); + while (c = *++s) + { + if (!isalnum(c) && c != '_' && c != '$') + return (0); + } + return (1); +} + + +output_defines() +{ + register int c, i; + register char *s; + + for (i = 2; i < ntokens; ++i) + { + s = symbol_name[i]; + if (is_C_identifier(s)) + { + fprintf(code_file, "#define "); + if (dflag) fprintf(defines_file, "#define "); + c = *s; + if (c == '"') + { + while ((c = *++s) != '"') + { + putc(c, code_file); + if (dflag) putc(c, defines_file); + } + } + else + { + do + { + putc(c, code_file); + if (dflag) putc(c, defines_file); + } + while (c = *++s); + } + ++outline; + fprintf(code_file, " %d\n", symbol_value[i]); + if (dflag) fprintf(defines_file, " %d\n", symbol_value[i]); + } + } + + ++outline; + fprintf(code_file, "#define YYERRCODE %d\n", symbol_value[1]); + + if (dflag && unionized) + { + fclose(union_file); + union_file = fopen(union_file_name, "r"); + if (union_file == NULL) open_error(union_file_name); + while ((c = getc(union_file)) != EOF) + putc(c, defines_file); + fprintf(defines_file, " YYSTYPE;\nextern YYSTYPE %slval;\n", + symbol_prefix); + } +} + + +output_stored_text() +{ + register int c; + register FILE *in, *out; + + fclose(text_file); + text_file = fopen(text_file_name, "r"); + if (text_file == NULL) + open_error(text_file_name); + in = text_file; + if ((c = getc(in)) == EOF) + return; + out = code_file; + if (c == '\n') + ++outline; + putc(c, out); + while ((c = getc(in)) != EOF) + { + if (c == '\n') + ++outline; + putc(c, out); + } + if (!lflag) + fprintf(out, line_format, ++outline + 1, code_file_name); +} + + +output_debug() +{ + register int i, j, k, max; + char **symnam, *s; + + ++outline; + fprintf(code_file, "#define YYFINAL %d\n", final_state); + outline += 3; + fprintf(code_file, "#ifndef YYDEBUG\n#define YYDEBUG %d\n#endif\n", + tflag); + if (rflag) + fprintf(output_file, "#ifndef YYDEBUG\n#define YYDEBUG %d\n#endif\n", + tflag); + + max = 0; + for (i = 2; i < ntokens; ++i) + if (symbol_value[i] > max) + max = symbol_value[i]; + ++outline; + fprintf(code_file, "#define YYMAXTOKEN %d\n", max); + + symnam = (char **) MALLOC((max+1)*sizeof(char *)); + if (symnam == 0) no_space(); + + /* Note that it is not necessary to initialize the element */ + /* symnam[max]. */ + for (i = 0; i < max; ++i) + symnam[i] = 0; + for (i = ntokens - 1; i >= 2; --i) + symnam[symbol_value[i]] = symbol_name[i]; + symnam[0] = "end-of-file"; + + if (!rflag) ++outline; + fprintf(output_file, "#if YYDEBUG\nchar *%sname[] = {", symbol_prefix); + j = 80; + for (i = 0; i <= max; ++i) + { + if (s = symnam[i]) + { + if (s[0] == '"') + { + k = 7; + while (*++s != '"') + { + ++k; + if (*s == '\\') + { + k += 2; + if (*++s == '\\') + ++k; + } + } + j += k; + if (j > 80) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = k; + } + fprintf(output_file, "\"\\\""); + s = symnam[i]; + while (*++s != '"') + { + if (*s == '\\') + { + fprintf(output_file, "\\\\"); + if (*++s == '\\') + fprintf(output_file, "\\\\"); + else + putc(*s, output_file); + } + else + putc(*s, output_file); + } + fprintf(output_file, "\\\"\","); + } + else if (s[0] == '\'') + { + if (s[1] == '"') + { + j += 7; + if (j > 80) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 7; + } + fprintf(output_file, "\"'\\\"'\","); + } + else + { + k = 5; + while (*++s != '\'') + { + ++k; + if (*s == '\\') + { + k += 2; + if (*++s == '\\') + ++k; + } + } + j += k; + if (j > 80) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = k; + } + fprintf(output_file, "\"'"); + s = symnam[i]; + while (*++s != '\'') + { + if (*s == '\\') + { + fprintf(output_file, "\\\\"); + if (*++s == '\\') + fprintf(output_file, "\\\\"); + else + putc(*s, output_file); + } + else + putc(*s, output_file); + } + fprintf(output_file, "'\","); + } + } + else + { + k = strlen(s) + 3; + j += k; + if (j > 80) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = k; + } + putc('"', output_file); + do { putc(*s, output_file); } while (*++s); + fprintf(output_file, "\","); + } + } + else + { + j += 2; + if (j > 80) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 2; + } + fprintf(output_file, "0,"); + } + } + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + FREE(symnam); + + if (!rflag) ++outline; + fprintf(output_file, "char *%srule[] = {\n", symbol_prefix); + for (i = 2; i < nrules; ++i) + { + fprintf(output_file, "\"%s :", symbol_name[rlhs[i]]); + for (j = rrhs[i]; ritem[j] > 0; ++j) + { + s = symbol_name[ritem[j]]; + if (s[0] == '"') + { + fprintf(output_file, " \\\""); + while (*++s != '"') + { + if (*s == '\\') + { + if (s[1] == '\\') + fprintf(output_file, "\\\\\\\\"); + else + fprintf(output_file, "\\\\%c", s[1]); + ++s; + } + else + putc(*s, output_file); + } + fprintf(output_file, "\\\""); + } + else if (s[0] == '\'') + { + if (s[1] == '"') + fprintf(output_file, " '\\\"'"); + else if (s[1] == '\\') + { + if (s[2] == '\\') + fprintf(output_file, " '\\\\\\\\"); + else + fprintf(output_file, " '\\\\%c", s[2]); + s += 2; + while (*++s != '\'') + putc(*s, output_file); + putc('\'', output_file); + } + else + fprintf(output_file, " '%c'", s[1]); + } + else + fprintf(output_file, " %s", s); + } + if (!rflag) ++outline; + fprintf(output_file, "\",\n"); + } + + if (!rflag) outline += 2; + fprintf(output_file, "};\n#endif\n"); +} + + +output_stype() +{ + if (!unionized && ntags == 0) + { + outline += 3; + fprintf(code_file, "#ifndef YYSTYPE\ntypedef int YYSTYPE;\n#endif\n"); + } +} + + +output_trailing_text() +{ + register int c, last; + register FILE *in, *out; + + if (line == 0) + return; + + in = input_file; + out = code_file; + c = *cptr; + if (c == '\n') + { + ++lineno; + if ((c = getc(in)) == EOF) + return; + if (!lflag) + { + ++outline; + fprintf(out, line_format, lineno, input_file_name); + } + if (c == '\n') + ++outline; + putc(c, out); + last = c; + } + else + { + if (!lflag) + { + ++outline; + fprintf(out, line_format, lineno, input_file_name); + } + do { putc(c, out); } while ((c = *++cptr) != '\n'); + ++outline; + putc('\n', out); + last = '\n'; + } + + while ((c = getc(in)) != EOF) + { + if (c == '\n') + ++outline; + putc(c, out); + last = c; + } + + if (last != '\n') + { + ++outline; + putc('\n', out); + } + if (!lflag) + fprintf(out, line_format, ++outline + 1, code_file_name); +} + + +output_semantic_actions() +{ + register int c, last; + register FILE *out; + + fclose(action_file); + action_file = fopen(action_file_name, "r"); + if (action_file == NULL) + open_error(action_file_name); + + if ((c = getc(action_file)) == EOF) + return; + + out = code_file; + last = c; + if (c == '\n') + ++outline; + putc(c, out); + while ((c = getc(action_file)) != EOF) + { + if (c == '\n') + ++outline; + putc(c, out); + last = c; + } + + if (last != '\n') + { + ++outline; + putc('\n', out); + } + + if (!lflag) + fprintf(out, line_format, ++outline + 1, code_file_name); +} + + +free_itemsets() +{ + register core *cp, *next; + + FREE(state_table); + for (cp = first_state; cp; cp = next) + { + next = cp->next; + FREE(cp); + } +} + + +free_shifts() +{ + register shifts *sp, *next; + + FREE(shift_table); + for (sp = first_shift; sp; sp = next) + { + next = sp->next; + FREE(sp); + } +} + + + +free_reductions() +{ + register reductions *rp, *next; + + FREE(reduction_table); + for (rp = first_reduction; rp; rp = next) + { + next = rp->next; + FREE(rp); + } +} diff --git a/usr.bin/yacc/reader.c b/usr.bin/yacc/reader.c new file mode 100644 index 0000000..3b724d3 --- /dev/null +++ b/usr.bin/yacc/reader.c @@ -0,0 +1,1810 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)reader.c 5.7 (Berkeley) 1/20/91"; +#endif /* not lint */ + +#include "defs.h" + +/* The line size must be a positive integer. One hundred was chosen */ +/* because few lines in Yacc input grammars exceed 100 characters. */ +/* Note that if a line exceeds LINESIZE characters, the line buffer */ +/* will be expanded to accomodate it. */ + +#define LINESIZE 100 + +char *cache; +int cinc, cache_size; + +int ntags, tagmax; +char **tag_table; + +char saw_eof, unionized; +char *cptr, *line; +int linesize; + +bucket *goal; +int prec; +int gensym; +char last_was_action; + +int maxitems; +bucket **pitem; + +int maxrules; +bucket **plhs; + +int name_pool_size; +char *name_pool; + +char line_format[] = "#line %d \"%s\"\n"; + + +cachec(c) +int c; +{ + assert(cinc >= 0); + if (cinc >= cache_size) + { + cache_size += 256; + cache = REALLOC(cache, cache_size); + if (cache == 0) no_space(); + } + cache[cinc] = c; + ++cinc; +} + + +get_line() +{ + register FILE *f = input_file; + register int c; + register int i; + + if (saw_eof || (c = getc(f)) == EOF) + { + if (line) { FREE(line); line = 0; } + cptr = 0; + saw_eof = 1; + return; + } + + if (line == 0 || linesize != (LINESIZE + 1)) + { + if (line) FREE(line); + linesize = LINESIZE + 1; + line = MALLOC(linesize); + if (line == 0) no_space(); + } + + i = 0; + ++lineno; + for (;;) + { + line[i] = c; + if (c == '\n') { cptr = line; return; } + if (++i >= linesize) + { + linesize += LINESIZE; + line = REALLOC(line, linesize); + if (line == 0) no_space(); + } + c = getc(f); + if (c == EOF) + { + line[i] = '\n'; + saw_eof = 1; + cptr = line; + return; + } + } +} + + +char * +dup_line() +{ + register char *p, *s, *t; + + if (line == 0) return (0); + s = line; + while (*s != '\n') ++s; + p = MALLOC(s - line + 1); + if (p == 0) no_space(); + + s = line; + t = p; + while ((*t++ = *s++) != '\n') continue; + return (p); +} + + +skip_comment() +{ + register char *s; + + int st_lineno = lineno; + char *st_line = dup_line(); + char *st_cptr = st_line + (cptr - line); + + s = cptr + 2; + for (;;) + { + if (*s == '*' && s[1] == '/') + { + cptr = s + 2; + FREE(st_line); + return; + } + if (*s == '\n') + { + get_line(); + if (line == 0) + unterminated_comment(st_lineno, st_line, st_cptr); + s = cptr; + } + else + ++s; + } +} + + +int +nextc() +{ + register char *s; + + if (line == 0) + { + get_line(); + if (line == 0) + return (EOF); + } + + s = cptr; + for (;;) + { + switch (*s) + { + case '\n': + get_line(); + if (line == 0) return (EOF); + s = cptr; + break; + + case ' ': + case '\t': + case '\f': + case '\r': + case '\v': + case ',': + case ';': + ++s; + break; + + case '\\': + cptr = s; + return ('%'); + + case '/': + if (s[1] == '*') + { + cptr = s; + skip_comment(); + s = cptr; + break; + } + else if (s[1] == '/') + { + get_line(); + if (line == 0) return (EOF); + s = cptr; + break; + } + /* fall through */ + + default: + cptr = s; + return (*s); + } + } +} + + +int +keyword() +{ + register int c; + char *t_cptr = cptr; + + c = *++cptr; + if (isalpha(c)) + { + cinc = 0; + for (;;) + { + if (isalpha(c)) + { + if (isupper(c)) c = tolower(c); + cachec(c); + } + else if (isdigit(c) || c == '_' || c == '.' || c == '$') + cachec(c); + else + break; + c = *++cptr; + } + cachec(NUL); + + if (strcmp(cache, "token") == 0 || strcmp(cache, "term") == 0) + return (TOKEN); + if (strcmp(cache, "type") == 0) + return (TYPE); + if (strcmp(cache, "left") == 0) + return (LEFT); + if (strcmp(cache, "right") == 0) + return (RIGHT); + if (strcmp(cache, "nonassoc") == 0 || strcmp(cache, "binary") == 0) + return (NONASSOC); + if (strcmp(cache, "start") == 0) + return (START); + if (strcmp(cache, "union") == 0) + return (UNION); + if (strcmp(cache, "ident") == 0) + return (IDENT); + } + else + { + ++cptr; + if (c == '{') + return (TEXT); + if (c == '%' || c == '\\') + return (MARK); + if (c == '<') + return (LEFT); + if (c == '>') + return (RIGHT); + if (c == '0') + return (TOKEN); + if (c == '2') + return (NONASSOC); + } + syntax_error(lineno, line, t_cptr); + /*NOTREACHED*/ +} + + +copy_ident() +{ + register int c; + register FILE *f = output_file; + + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c != '"') syntax_error(lineno, line, cptr); + ++outline; + fprintf(f, "#ident \""); + for (;;) + { + c = *++cptr; + if (c == '\n') + { + fprintf(f, "\"\n"); + return; + } + putc(c, f); + if (c == '"') + { + putc('\n', f); + ++cptr; + return; + } + } +} + + +copy_text() +{ + register int c; + int quote; + register FILE *f = text_file; + int need_newline = 0; + int t_lineno = lineno; + char *t_line = dup_line(); + char *t_cptr = t_line + (cptr - line - 2); + + if (*cptr == '\n') + { + get_line(); + if (line == 0) + unterminated_text(t_lineno, t_line, t_cptr); + } + if (!lflag) fprintf(f, line_format, lineno, input_file_name); + +loop: + c = *cptr++; + switch (c) + { + case '\n': + next_line: + putc('\n', f); + need_newline = 0; + get_line(); + if (line) goto loop; + unterminated_text(t_lineno, t_line, t_cptr); + + case '\'': + case '"': + { + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line - 1); + + quote = c; + putc(c, f); + for (;;) + { + c = *cptr++; + putc(c, f); + if (c == quote) + { + need_newline = 1; + FREE(s_line); + goto loop; + } + if (c == '\n') + unterminated_string(s_lineno, s_line, s_cptr); + if (c == '\\') + { + c = *cptr++; + putc(c, f); + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_string(s_lineno, s_line, s_cptr); + } + } + } + } + + case '/': + putc(c, f); + need_newline = 1; + c = *cptr; + if (c == '/') + { + putc('*', f); + while ((c = *++cptr) != '\n') + { + if (c == '*' && cptr[1] == '/') + fprintf(f, "* "); + else + putc(c, f); + } + fprintf(f, "*/"); + goto next_line; + } + if (c == '*') + { + int c_lineno = lineno; + char *c_line = dup_line(); + char *c_cptr = c_line + (cptr - line - 1); + + putc('*', f); + ++cptr; + for (;;) + { + c = *cptr++; + putc(c, f); + if (c == '*' && *cptr == '/') + { + putc('/', f); + ++cptr; + FREE(c_line); + goto loop; + } + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_comment(c_lineno, c_line, c_cptr); + } + } + } + need_newline = 1; + goto loop; + + case '%': + case '\\': + if (*cptr == '}') + { + if (need_newline) putc('\n', f); + ++cptr; + FREE(t_line); + return; + } + /* fall through */ + + default: + putc(c, f); + need_newline = 1; + goto loop; + } +} + + +copy_union() +{ + register int c; + int quote; + int depth; + int u_lineno = lineno; + char *u_line = dup_line(); + char *u_cptr = u_line + (cptr - line - 6); + + if (unionized) over_unionized(cptr - 6); + unionized = 1; + + if (!lflag) + fprintf(text_file, line_format, lineno, input_file_name); + + fprintf(text_file, "typedef union"); + if (dflag) fprintf(union_file, "typedef union"); + + depth = 0; +loop: + c = *cptr++; + putc(c, text_file); + if (dflag) putc(c, union_file); + switch (c) + { + case '\n': + next_line: + get_line(); + if (line == 0) unterminated_union(u_lineno, u_line, u_cptr); + goto loop; + + case '{': + ++depth; + goto loop; + + case '}': + if (--depth == 0) + { + fprintf(text_file, " YYSTYPE;\n"); + FREE(u_line); + return; + } + goto loop; + + case '\'': + case '"': + { + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line - 1); + + quote = c; + for (;;) + { + c = *cptr++; + putc(c, text_file); + if (dflag) putc(c, union_file); + if (c == quote) + { + FREE(s_line); + goto loop; + } + if (c == '\n') + unterminated_string(s_lineno, s_line, s_cptr); + if (c == '\\') + { + c = *cptr++; + putc(c, text_file); + if (dflag) putc(c, union_file); + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_string(s_lineno, s_line, s_cptr); + } + } + } + } + + case '/': + c = *cptr; + if (c == '/') + { + putc('*', text_file); + if (dflag) putc('*', union_file); + while ((c = *++cptr) != '\n') + { + if (c == '*' && cptr[1] == '/') + { + fprintf(text_file, "* "); + if (dflag) fprintf(union_file, "* "); + } + else + { + putc(c, text_file); + if (dflag) putc(c, union_file); + } + } + fprintf(text_file, "*/\n"); + if (dflag) fprintf(union_file, "*/\n"); + goto next_line; + } + if (c == '*') + { + int c_lineno = lineno; + char *c_line = dup_line(); + char *c_cptr = c_line + (cptr - line - 1); + + putc('*', text_file); + if (dflag) putc('*', union_file); + ++cptr; + for (;;) + { + c = *cptr++; + putc(c, text_file); + if (dflag) putc(c, union_file); + if (c == '*' && *cptr == '/') + { + putc('/', text_file); + if (dflag) putc('/', union_file); + ++cptr; + FREE(c_line); + goto loop; + } + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_comment(c_lineno, c_line, c_cptr); + } + } + } + goto loop; + + default: + goto loop; + } +} + + +int +hexval(c) +int c; +{ + if (c >= '0' && c <= '9') + return (c - '0'); + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + return (-1); +} + + +bucket * +get_literal() +{ + register int c, quote; + register int i; + register int n; + register char *s; + register bucket *bp; + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line); + + quote = *cptr++; + cinc = 0; + for (;;) + { + c = *cptr++; + if (c == quote) break; + if (c == '\n') unterminated_string(s_lineno, s_line, s_cptr); + if (c == '\\') + { + char *c_cptr = cptr - 1; + + c = *cptr++; + switch (c) + { + case '\n': + get_line(); + if (line == 0) unterminated_string(s_lineno, s_line, s_cptr); + continue; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + n = c - '0'; + c = *cptr; + if (IS_OCTAL(c)) + { + n = (n << 3) + (c - '0'); + c = *++cptr; + if (IS_OCTAL(c)) + { + n = (n << 3) + (c - '0'); + ++cptr; + } + } + if (n > MAXCHAR) illegal_character(c_cptr); + c = n; + break; + + case 'x': + c = *cptr++; + n = hexval(c); + if (n < 0 || n >= 16) + illegal_character(c_cptr); + for (;;) + { + c = *cptr; + i = hexval(c); + if (i < 0 || i >= 16) break; + ++cptr; + n = (n << 4) + i; + if (n > MAXCHAR) illegal_character(c_cptr); + } + c = n; + break; + + case 'a': c = 7; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + } + } + cachec(c); + } + FREE(s_line); + + n = cinc; + s = MALLOC(n); + if (s == 0) no_space(); + + for (i = 0; i < n; ++i) + s[i] = cache[i]; + + cinc = 0; + if (n == 1) + cachec('\''); + else + cachec('"'); + + for (i = 0; i < n; ++i) + { + c = ((unsigned char *)s)[i]; + if (c == '\\' || c == cache[0]) + { + cachec('\\'); + cachec(c); + } + else if (isprint(c)) + cachec(c); + else + { + cachec('\\'); + switch (c) + { + case 7: cachec('a'); break; + case '\b': cachec('b'); break; + case '\f': cachec('f'); break; + case '\n': cachec('n'); break; + case '\r': cachec('r'); break; + case '\t': cachec('t'); break; + case '\v': cachec('v'); break; + default: + cachec(((c >> 6) & 7) + '0'); + cachec(((c >> 3) & 7) + '0'); + cachec((c & 7) + '0'); + break; + } + } + } + + if (n == 1) + cachec('\''); + else + cachec('"'); + + cachec(NUL); + bp = lookup(cache); + bp->class = TERM; + if (n == 1 && bp->value == UNDEFINED) + bp->value = *(unsigned char *)s; + FREE(s); + + return (bp); +} + + +int +is_reserved(name) +char *name; +{ + char *s; + + if (strcmp(name, ".") == 0 || + strcmp(name, "$accept") == 0 || + strcmp(name, "$end") == 0) + return (1); + + if (name[0] == '$' && name[1] == '$' && isdigit(name[2])) + { + s = name + 3; + while (isdigit(*s)) ++s; + if (*s == NUL) return (1); + } + + return (0); +} + + +bucket * +get_name() +{ + register int c; + + cinc = 0; + for (c = *cptr; IS_IDENT(c); c = *++cptr) + cachec(c); + cachec(NUL); + + if (is_reserved(cache)) used_reserved(cache); + + return (lookup(cache)); +} + + +int +get_number() +{ + register int c; + register int n; + + n = 0; + for (c = *cptr; isdigit(c); c = *++cptr) + n = 10*n + (c - '0'); + + return (n); +} + + +char * +get_tag() +{ + register int c; + register int i; + register char *s; + int t_lineno = lineno; + char *t_line = dup_line(); + char *t_cptr = t_line + (cptr - line); + + ++cptr; + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (!isalpha(c) && c != '_' && c != '$') + illegal_tag(t_lineno, t_line, t_cptr); + + cinc = 0; + do { cachec(c); c = *++cptr; } while (IS_IDENT(c)); + cachec(NUL); + + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c != '>') + illegal_tag(t_lineno, t_line, t_cptr); + ++cptr; + + for (i = 0; i < ntags; ++i) + { + if (strcmp(cache, tag_table[i]) == 0) + return (tag_table[i]); + } + + if (ntags >= tagmax) + { + tagmax += 16; + tag_table = (char **) + (tag_table ? REALLOC(tag_table, tagmax*sizeof(char *)) + : MALLOC(tagmax*sizeof(char *))); + if (tag_table == 0) no_space(); + } + + s = MALLOC(cinc); + if (s == 0) no_space(); + strcpy(s, cache); + tag_table[ntags] = s; + ++ntags; + FREE(t_line); + return (s); +} + + +declare_tokens(assoc) +int assoc; +{ + register int c; + register bucket *bp; + int value; + char *tag = 0; + + if (assoc != TOKEN) ++prec; + + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c == '<') + { + tag = get_tag(); + c = nextc(); + if (c == EOF) unexpected_EOF(); + } + + for (;;) + { + if (isalpha(c) || c == '_' || c == '.' || c == '$') + bp = get_name(); + else if (c == '\'' || c == '"') + bp = get_literal(); + else + return; + + if (bp == goal) tokenized_start(bp->name); + bp->class = TERM; + + if (tag) + { + if (bp->tag && tag != bp->tag) + retyped_warning(bp->name); + bp->tag = tag; + } + + if (assoc != TOKEN) + { + if (bp->prec && prec != bp->prec) + reprec_warning(bp->name); + bp->assoc = assoc; + bp->prec = prec; + } + + c = nextc(); + if (c == EOF) unexpected_EOF(); + value = UNDEFINED; + if (isdigit(c)) + { + value = get_number(); + if (bp->value != UNDEFINED && value != bp->value) + revalued_warning(bp->name); + bp->value = value; + c = nextc(); + if (c == EOF) unexpected_EOF(); + } + } +} + + +declare_types() +{ + register int c; + register bucket *bp; + char *tag; + + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c != '<') syntax_error(lineno, line, cptr); + tag = get_tag(); + + for (;;) + { + c = nextc(); + if (isalpha(c) || c == '_' || c == '.' || c == '$') + bp = get_name(); + else if (c == '\'' || c == '"') + bp = get_literal(); + else + return; + + if (bp->tag && tag != bp->tag) + retyped_warning(bp->name); + bp->tag = tag; + } +} + + +declare_start() +{ + register int c; + register bucket *bp; + + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (!isalpha(c) && c != '_' && c != '.' && c != '$') + syntax_error(lineno, line, cptr); + bp = get_name(); + if (bp->class == TERM) + terminal_start(bp->name); + if (goal && goal != bp) + restarted_warning(); + goal = bp; +} + + +read_declarations() +{ + register int c, k; + + cache_size = 256; + cache = MALLOC(cache_size); + if (cache == 0) no_space(); + + for (;;) + { + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c != '%') syntax_error(lineno, line, cptr); + switch (k = keyword()) + { + case MARK: + return; + + case IDENT: + copy_ident(); + break; + + case TEXT: + copy_text(); + break; + + case UNION: + copy_union(); + break; + + case TOKEN: + case LEFT: + case RIGHT: + case NONASSOC: + declare_tokens(k); + break; + + case TYPE: + declare_types(); + break; + + case START: + declare_start(); + break; + } + } +} + + +initialize_grammar() +{ + nitems = 4; + maxitems = 300; + pitem = (bucket **) MALLOC(maxitems*sizeof(bucket *)); + if (pitem == 0) no_space(); + pitem[0] = 0; + pitem[1] = 0; + pitem[2] = 0; + pitem[3] = 0; + + nrules = 3; + maxrules = 100; + plhs = (bucket **) MALLOC(maxrules*sizeof(bucket *)); + if (plhs == 0) no_space(); + plhs[0] = 0; + plhs[1] = 0; + plhs[2] = 0; + rprec = (short *) MALLOC(maxrules*sizeof(short)); + if (rprec == 0) no_space(); + rprec[0] = 0; + rprec[1] = 0; + rprec[2] = 0; + rassoc = (char *) MALLOC(maxrules*sizeof(char)); + if (rassoc == 0) no_space(); + rassoc[0] = TOKEN; + rassoc[1] = TOKEN; + rassoc[2] = TOKEN; +} + + +expand_items() +{ + maxitems += 300; + pitem = (bucket **) REALLOC(pitem, maxitems*sizeof(bucket *)); + if (pitem == 0) no_space(); +} + + +expand_rules() +{ + maxrules += 100; + plhs = (bucket **) REALLOC(plhs, maxrules*sizeof(bucket *)); + if (plhs == 0) no_space(); + rprec = (short *) REALLOC(rprec, maxrules*sizeof(short)); + if (rprec == 0) no_space(); + rassoc = (char *) REALLOC(rassoc, maxrules*sizeof(char)); + if (rassoc == 0) no_space(); +} + + +advance_to_start() +{ + register int c; + register bucket *bp; + char *s_cptr; + int s_lineno; + + for (;;) + { + c = nextc(); + if (c != '%') break; + s_cptr = cptr; + switch (keyword()) + { + case MARK: + no_grammar(); + + case TEXT: + copy_text(); + break; + + case START: + declare_start(); + break; + + default: + syntax_error(lineno, line, s_cptr); + } + } + + c = nextc(); + if (!isalpha(c) && c != '_' && c != '.' && c != '_') + syntax_error(lineno, line, cptr); + bp = get_name(); + if (goal == 0) + { + if (bp->class == TERM) + terminal_start(bp->name); + goal = bp; + } + + s_lineno = lineno; + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c != ':') syntax_error(lineno, line, cptr); + start_rule(bp, s_lineno); + ++cptr; +} + + +start_rule(bp, s_lineno) +register bucket *bp; +int s_lineno; +{ + if (bp->class == TERM) + terminal_lhs(s_lineno); + bp->class = NONTERM; + if (nrules >= maxrules) + expand_rules(); + plhs[nrules] = bp; + rprec[nrules] = UNDEFINED; + rassoc[nrules] = TOKEN; +} + + +end_rule() +{ + register int i; + + if (!last_was_action && plhs[nrules]->tag) + { + for (i = nitems - 1; pitem[i]; --i) continue; + if (pitem[i+1] == 0 || pitem[i+1]->tag != plhs[nrules]->tag) + default_action_warning(); + } + + last_was_action = 0; + if (nitems >= maxitems) expand_items(); + pitem[nitems] = 0; + ++nitems; + ++nrules; +} + + +insert_empty_rule() +{ + register bucket *bp, **bpp; + + assert(cache); + sprintf(cache, "$$%d", ++gensym); + bp = make_bucket(cache); + last_symbol->next = bp; + last_symbol = bp; + bp->tag = plhs[nrules]->tag; + bp->class = NONTERM; + + if ((nitems += 2) > maxitems) + expand_items(); + bpp = pitem + nitems - 1; + *bpp-- = bp; + while (bpp[0] = bpp[-1]) --bpp; + + if (++nrules >= maxrules) + expand_rules(); + plhs[nrules] = plhs[nrules-1]; + plhs[nrules-1] = bp; + rprec[nrules] = rprec[nrules-1]; + rprec[nrules-1] = 0; + rassoc[nrules] = rassoc[nrules-1]; + rassoc[nrules-1] = TOKEN; +} + + +add_symbol() +{ + register int c; + register bucket *bp; + int s_lineno = lineno; + + c = *cptr; + if (c == '\'' || c == '"') + bp = get_literal(); + else + bp = get_name(); + + c = nextc(); + if (c == ':') + { + end_rule(); + start_rule(bp, s_lineno); + ++cptr; + return; + } + + if (last_was_action) + insert_empty_rule(); + last_was_action = 0; + + if (++nitems > maxitems) + expand_items(); + pitem[nitems-1] = bp; +} + + +copy_action() +{ + register int c; + register int i, n; + int depth; + int quote; + char *tag; + register FILE *f = action_file; + int a_lineno = lineno; + char *a_line = dup_line(); + char *a_cptr = a_line + (cptr - line); + + if (last_was_action) + insert_empty_rule(); + last_was_action = 1; + + fprintf(f, "case %d:\n", nrules - 2); + if (!lflag) + fprintf(f, line_format, lineno, input_file_name); + if (*cptr == '=') ++cptr; + + n = 0; + for (i = nitems - 1; pitem[i]; --i) ++n; + + depth = 0; +loop: + c = *cptr; + if (c == '$') + { + if (cptr[1] == '<') + { + int d_lineno = lineno; + char *d_line = dup_line(); + char *d_cptr = d_line + (cptr - line); + + ++cptr; + tag = get_tag(); + c = *cptr; + if (c == '$') + { + fprintf(f, "yyval.%s", tag); + ++cptr; + FREE(d_line); + goto loop; + } + else if (isdigit(c)) + { + i = get_number(); + if (i > n) dollar_warning(d_lineno, i); + fprintf(f, "yyvsp[%d].%s", i - n, tag); + FREE(d_line); + goto loop; + } + else if (c == '-' && isdigit(cptr[1])) + { + ++cptr; + i = -get_number() - n; + fprintf(f, "yyvsp[%d].%s", i, tag); + FREE(d_line); + goto loop; + } + else + dollar_error(d_lineno, d_line, d_cptr); + } + else if (cptr[1] == '$') + { + if (ntags) + { + tag = plhs[nrules]->tag; + if (tag == 0) untyped_lhs(); + fprintf(f, "yyval.%s", tag); + } + else + fprintf(f, "yyval"); + cptr += 2; + goto loop; + } + else if (isdigit(cptr[1])) + { + ++cptr; + i = get_number(); + if (ntags) + { + if (i <= 0 || i > n) + unknown_rhs(i); + tag = pitem[nitems + i - n - 1]->tag; + if (tag == 0) untyped_rhs(i, pitem[nitems + i - n - 1]->name); + fprintf(f, "yyvsp[%d].%s", i - n, tag); + } + else + { + if (i > n) + dollar_warning(lineno, i); + fprintf(f, "yyvsp[%d]", i - n); + } + goto loop; + } + else if (cptr[1] == '-') + { + cptr += 2; + i = get_number(); + if (ntags) + unknown_rhs(-i); + fprintf(f, "yyvsp[%d]", -i - n); + goto loop; + } + } + if (isalpha(c) || c == '_' || c == '$') + { + do + { + putc(c, f); + c = *++cptr; + } while (isalnum(c) || c == '_' || c == '$'); + goto loop; + } + putc(c, f); + ++cptr; + switch (c) + { + case '\n': + next_line: + get_line(); + if (line) goto loop; + unterminated_action(a_lineno, a_line, a_cptr); + + case ';': + if (depth > 0) goto loop; + fprintf(f, "\nbreak;\n"); + return; + + case '{': + ++depth; + goto loop; + + case '}': + if (--depth > 0) goto loop; + fprintf(f, "\nbreak;\n"); + return; + + case '\'': + case '"': + { + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line - 1); + + quote = c; + for (;;) + { + c = *cptr++; + putc(c, f); + if (c == quote) + { + FREE(s_line); + goto loop; + } + if (c == '\n') + unterminated_string(s_lineno, s_line, s_cptr); + if (c == '\\') + { + c = *cptr++; + putc(c, f); + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_string(s_lineno, s_line, s_cptr); + } + } + } + } + + case '/': + c = *cptr; + if (c == '/') + { + putc('*', f); + while ((c = *++cptr) != '\n') + { + if (c == '*' && cptr[1] == '/') + fprintf(f, "* "); + else + putc(c, f); + } + fprintf(f, "*/\n"); + goto next_line; + } + if (c == '*') + { + int c_lineno = lineno; + char *c_line = dup_line(); + char *c_cptr = c_line + (cptr - line - 1); + + putc('*', f); + ++cptr; + for (;;) + { + c = *cptr++; + putc(c, f); + if (c == '*' && *cptr == '/') + { + putc('/', f); + ++cptr; + FREE(c_line); + goto loop; + } + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_comment(c_lineno, c_line, c_cptr); + } + } + } + goto loop; + + default: + goto loop; + } +} + + +int +mark_symbol() +{ + register int c; + register bucket *bp; + + c = cptr[1]; + if (c == '%' || c == '\\') + { + cptr += 2; + return (1); + } + + if (c == '=') + cptr += 2; + else if ((c == 'p' || c == 'P') && + ((c = cptr[2]) == 'r' || c == 'R') && + ((c = cptr[3]) == 'e' || c == 'E') && + ((c = cptr[4]) == 'c' || c == 'C') && + ((c = cptr[5], !IS_IDENT(c)))) + cptr += 5; + else + syntax_error(lineno, line, cptr); + + c = nextc(); + if (isalpha(c) || c == '_' || c == '.' || c == '$') + bp = get_name(); + else if (c == '\'' || c == '"') + bp = get_literal(); + else + { + syntax_error(lineno, line, cptr); + /*NOTREACHED*/ + } + + if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules]) + prec_redeclared(); + + rprec[nrules] = bp->prec; + rassoc[nrules] = bp->assoc; + return (0); +} + + +read_grammar() +{ + register int c; + + initialize_grammar(); + advance_to_start(); + + for (;;) + { + c = nextc(); + if (c == EOF) break; + if (isalpha(c) || c == '_' || c == '.' || c == '$' || c == '\'' || + c == '"') + add_symbol(); + else if (c == '{' || c == '=') + copy_action(); + else if (c == '|') + { + end_rule(); + start_rule(plhs[nrules-1], 0); + ++cptr; + } + else if (c == '%') + { + if (mark_symbol()) break; + } + else + syntax_error(lineno, line, cptr); + } + end_rule(); +} + + +free_tags() +{ + register int i; + + if (tag_table == 0) return; + + for (i = 0; i < ntags; ++i) + { + assert(tag_table[i]); + FREE(tag_table[i]); + } + FREE(tag_table); +} + + +pack_names() +{ + register bucket *bp; + register char *p, *s, *t; + + name_pool_size = 13; /* 13 == sizeof("$end") + sizeof("$accept") */ + for (bp = first_symbol; bp; bp = bp->next) + name_pool_size += strlen(bp->name) + 1; + name_pool = MALLOC(name_pool_size); + if (name_pool == 0) no_space(); + + strcpy(name_pool, "$accept"); + strcpy(name_pool+8, "$end"); + t = name_pool + 13; + for (bp = first_symbol; bp; bp = bp->next) + { + p = t; + s = bp->name; + while (*t++ = *s++) continue; + FREE(bp->name); + bp->name = p; + } +} + + +check_symbols() +{ + register bucket *bp; + + if (goal->class == UNKNOWN) + undefined_goal(goal->name); + + for (bp = first_symbol; bp; bp = bp->next) + { + if (bp->class == UNKNOWN) + { + undefined_symbol_warning(bp->name); + bp->class = TERM; + } + } +} + + +pack_symbols() +{ + register bucket *bp; + register bucket **v; + register int i, j, k, n; + + nsyms = 2; + ntokens = 1; + for (bp = first_symbol; bp; bp = bp->next) + { + ++nsyms; + if (bp->class == TERM) ++ntokens; + } + start_symbol = ntokens; + nvars = nsyms - ntokens; + + symbol_name = (char **) MALLOC(nsyms*sizeof(char *)); + if (symbol_name == 0) no_space(); + symbol_value = (short *) MALLOC(nsyms*sizeof(short)); + if (symbol_value == 0) no_space(); + symbol_prec = (short *) MALLOC(nsyms*sizeof(short)); + if (symbol_prec == 0) no_space(); + symbol_assoc = MALLOC(nsyms); + if (symbol_assoc == 0) no_space(); + + v = (bucket **) MALLOC(nsyms*sizeof(bucket *)); + if (v == 0) no_space(); + + v[0] = 0; + v[start_symbol] = 0; + + i = 1; + j = start_symbol + 1; + for (bp = first_symbol; bp; bp = bp->next) + { + if (bp->class == TERM) + v[i++] = bp; + else + v[j++] = bp; + } + assert(i == ntokens && j == nsyms); + + for (i = 1; i < ntokens; ++i) + v[i]->index = i; + + goal->index = start_symbol + 1; + k = start_symbol + 2; + while (++i < nsyms) + if (v[i] != goal) + { + v[i]->index = k; + ++k; + } + + goal->value = 0; + k = 1; + for (i = start_symbol + 1; i < nsyms; ++i) + { + if (v[i] != goal) + { + v[i]->value = k; + ++k; + } + } + + k = 0; + for (i = 1; i < ntokens; ++i) + { + n = v[i]->value; + if (n > 256) + { + for (j = k++; j > 0 && symbol_value[j-1] > n; --j) + symbol_value[j] = symbol_value[j-1]; + symbol_value[j] = n; + } + } + + if (v[1]->value == UNDEFINED) + v[1]->value = 256; + + j = 0; + n = 257; + for (i = 2; i < ntokens; ++i) + { + if (v[i]->value == UNDEFINED) + { + while (j < k && n == symbol_value[j]) + { + while (++j < k && n == symbol_value[j]) continue; + ++n; + } + v[i]->value = n; + ++n; + } + } + + symbol_name[0] = name_pool + 8; + symbol_value[0] = 0; + symbol_prec[0] = 0; + symbol_assoc[0] = TOKEN; + for (i = 1; i < ntokens; ++i) + { + symbol_name[i] = v[i]->name; + symbol_value[i] = v[i]->value; + symbol_prec[i] = v[i]->prec; + symbol_assoc[i] = v[i]->assoc; + } + symbol_name[start_symbol] = name_pool; + symbol_value[start_symbol] = -1; + symbol_prec[start_symbol] = 0; + symbol_assoc[start_symbol] = TOKEN; + for (++i; i < nsyms; ++i) + { + k = v[i]->index; + symbol_name[k] = v[i]->name; + symbol_value[k] = v[i]->value; + symbol_prec[k] = v[i]->prec; + symbol_assoc[k] = v[i]->assoc; + } + + FREE(v); +} + + +pack_grammar() +{ + register int i, j; + int assoc, prec; + + ritem = (short *) MALLOC(nitems*sizeof(short)); + if (ritem == 0) no_space(); + rlhs = (short *) MALLOC(nrules*sizeof(short)); + if (rlhs == 0) no_space(); + rrhs = (short *) MALLOC((nrules+1)*sizeof(short)); + if (rrhs == 0) no_space(); + rprec = (short *) REALLOC(rprec, nrules*sizeof(short)); + if (rprec == 0) no_space(); + rassoc = REALLOC(rassoc, nrules); + if (rassoc == 0) no_space(); + + ritem[0] = -1; + ritem[1] = goal->index; + ritem[2] = 0; + ritem[3] = -2; + rlhs[0] = 0; + rlhs[1] = 0; + rlhs[2] = start_symbol; + rrhs[0] = 0; + rrhs[1] = 0; + rrhs[2] = 1; + + j = 4; + for (i = 3; i < nrules; ++i) + { + rlhs[i] = plhs[i]->index; + rrhs[i] = j; + assoc = TOKEN; + prec = 0; + while (pitem[j]) + { + ritem[j] = pitem[j]->index; + if (pitem[j]->class == TERM) + { + prec = pitem[j]->prec; + assoc = pitem[j]->assoc; + } + ++j; + } + ritem[j] = -i; + ++j; + if (rprec[i] == UNDEFINED) + { + rprec[i] = prec; + rassoc[i] = assoc; + } + } + rrhs[i] = j; + + FREE(plhs); + FREE(pitem); +} + + +print_grammar() +{ + register int i, j, k; + int spacing; + register FILE *f = verbose_file; + + if (!vflag) return; + + k = 1; + for (i = 2; i < nrules; ++i) + { + if (rlhs[i] != rlhs[i-1]) + { + if (i != 2) fprintf(f, "\n"); + fprintf(f, "%4d %s :", i - 2, symbol_name[rlhs[i]]); + spacing = strlen(symbol_name[rlhs[i]]) + 1; + } + else + { + fprintf(f, "%4d ", i - 2); + j = spacing; + while (--j >= 0) putc(' ', f); + putc('|', f); + } + + while (ritem[k] >= 0) + { + fprintf(f, " %s", symbol_name[ritem[k]]); + ++k; + } + ++k; + putc('\n', f); + } +} + + +reader() +{ + write_section(banner); + create_symbol_table(); + read_declarations(); + read_grammar(); + free_symbol_table(); + free_tags(); + pack_names(); + check_symbols(); + pack_symbols(); + pack_grammar(); + free_symbols(); + print_grammar(); +} diff --git a/usr.bin/yacc/skeleton.c b/usr.bin/yacc/skeleton.c new file mode 100644 index 0000000..1e51b2e --- /dev/null +++ b/usr.bin/yacc/skeleton.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)skeleton.c 5.7 (Berkeley) 5/24/93"; +#endif /* not lint */ + +#include "defs.h" + +/* The definition of yysccsid in the banner should be replaced with */ +/* a #pragma ident directive if the target C compiler supports */ +/* #pragma ident directives. */ +/* */ +/* If the skeleton is changed, the banner should be changed so that */ +/* the altered version can be easily distinguished from the original. */ +/* */ +/* The #defines included with the banner are there because they are */ +/* useful in subsequent code. The macros #defined in the header or */ +/* the body either are not useful outside of semantic actions or */ +/* are conditional. */ + +char *banner[] = +{ + "#ifndef lint", + "static char yysccsid[] = \"@(#)yaccpar 1.9 (Berkeley) 02/21/93\";", + "#endif", + "#define YYBYACC 1", + "#define YYMAJOR 1", + "#define YYMINOR 9", + "#define yyclearin (yychar=(-1))", + "#define yyerrok (yyerrflag=0)", + "#define YYRECOVERING (yyerrflag!=0)", + 0 +}; + + +char *tables[] = +{ + "extern short yylhs[];", + "extern short yylen[];", + "extern short yydefred[];", + "extern short yydgoto[];", + "extern short yysindex[];", + "extern short yyrindex[];", + "extern short yygindex[];", + "extern short yytable[];", + "extern short yycheck[];", + "#if YYDEBUG", + "extern char *yyname[];", + "extern char *yyrule[];", + "#endif", + 0 +}; + + +char *header[] = +{ + "#ifdef YYSTACKSIZE", + "#undef YYMAXDEPTH", + "#define YYMAXDEPTH YYSTACKSIZE", + "#else", + "#ifdef YYMAXDEPTH", + "#define YYSTACKSIZE YYMAXDEPTH", + "#else", + "#define YYSTACKSIZE 500", + "#define YYMAXDEPTH 500", + "#endif", + "#endif", + "int yydebug;", + "int yynerrs;", + "int yyerrflag;", + "int yychar;", + "short *yyssp;", + "YYSTYPE *yyvsp;", + "YYSTYPE yyval;", + "YYSTYPE yylval;", + "short yyss[YYSTACKSIZE];", + "YYSTYPE yyvs[YYSTACKSIZE];", + "#define yystacksize YYSTACKSIZE", + 0 +}; + + +char *body[] = +{ + "#define YYABORT goto yyabort", + "#define YYREJECT goto yyabort", + "#define YYACCEPT goto yyaccept", + "#define YYERROR goto yyerrlab", + "int", + "yyparse()", + "{", + " register int yym, yyn, yystate;", + "#if YYDEBUG", + " register char *yys;", + " extern char *getenv();", + "", + " if (yys = getenv(\"YYDEBUG\"))", + " {", + " yyn = *yys;", + " if (yyn >= '0' && yyn <= '9')", + " yydebug = yyn - '0';", + " }", + "#endif", + "", + " yynerrs = 0;", + " yyerrflag = 0;", + " yychar = (-1);", + "", + " yyssp = yyss;", + " yyvsp = yyvs;", + " *yyssp = yystate = 0;", + "", + "yyloop:", + " if (yyn = yydefred[yystate]) goto yyreduce;", + " if (yychar < 0)", + " {", + " if ((yychar = yylex()) < 0) yychar = 0;", + "#if YYDEBUG", + " if (yydebug)", + " {", + " yys = 0;", + " if (yychar <= YYMAXTOKEN) yys = yyname[yychar];", + " if (!yys) yys = \"illegal-symbol\";", + " printf(\"%sdebug: state %d, reading %d (%s)\\n\",", + " YYPREFIX, yystate, yychar, yys);", + " }", + "#endif", + " }", + " if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&", + " yyn <= YYTABLESIZE && yycheck[yyn] == yychar)", + " {", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: state %d, shifting to state %d\\n\",", + " YYPREFIX, yystate, yytable[yyn]);", + "#endif", + " if (yyssp >= yyss + yystacksize - 1)", + " {", + " goto yyoverflow;", + " }", + " *++yyssp = yystate = yytable[yyn];", + " *++yyvsp = yylval;", + " yychar = (-1);", + " if (yyerrflag > 0) --yyerrflag;", + " goto yyloop;", + " }", + " if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&", + " yyn <= YYTABLESIZE && yycheck[yyn] == yychar)", + " {", + " yyn = yytable[yyn];", + " goto yyreduce;", + " }", + " if (yyerrflag) goto yyinrecovery;", + "#ifdef lint", + " goto yynewerror;", + "#endif", + "yynewerror:", + " yyerror(\"syntax error\");", + "#ifdef lint", + " goto yyerrlab;", + "#endif", + "yyerrlab:", + " ++yynerrs;", + "yyinrecovery:", + " if (yyerrflag < 3)", + " {", + " yyerrflag = 3;", + " for (;;)", + " {", + " if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&", + " yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)", + " {", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: state %d, error recovery shifting\\", + " to state %d\\n\", YYPREFIX, *yyssp, yytable[yyn]);", + "#endif", + " if (yyssp >= yyss + yystacksize - 1)", + " {", + " goto yyoverflow;", + " }", + " *++yyssp = yystate = yytable[yyn];", + " *++yyvsp = yylval;", + " goto yyloop;", + " }", + " else", + " {", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: error recovery discarding state %d\ +\\n\",", + " YYPREFIX, *yyssp);", + "#endif", + " if (yyssp <= yyss) goto yyabort;", + " --yyssp;", + " --yyvsp;", + " }", + " }", + " }", + " else", + " {", + " if (yychar == 0) goto yyabort;", + "#if YYDEBUG", + " if (yydebug)", + " {", + " yys = 0;", + " if (yychar <= YYMAXTOKEN) yys = yyname[yychar];", + " if (!yys) yys = \"illegal-symbol\";", + " printf(\"%sdebug: state %d, error recovery discards token %d\ + (%s)\\n\",", + " YYPREFIX, yystate, yychar, yys);", + " }", + "#endif", + " yychar = (-1);", + " goto yyloop;", + " }", + "yyreduce:", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: state %d, reducing by rule %d (%s)\\n\",", + " YYPREFIX, yystate, yyn, yyrule[yyn]);", + "#endif", + " yym = yylen[yyn];", + " yyval = yyvsp[1-yym];", + " switch (yyn)", + " {", + 0 +}; + + +char *trailer[] = +{ + " }", + " yyssp -= yym;", + " yystate = *yyssp;", + " yyvsp -= yym;", + " yym = yylhs[yyn];", + " if (yystate == 0 && yym == 0)", + " {", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: after reduction, shifting from state 0 to\\", + " state %d\\n\", YYPREFIX, YYFINAL);", + "#endif", + " yystate = YYFINAL;", + " *++yyssp = YYFINAL;", + " *++yyvsp = yyval;", + " if (yychar < 0)", + " {", + " if ((yychar = yylex()) < 0) yychar = 0;", + "#if YYDEBUG", + " if (yydebug)", + " {", + " yys = 0;", + " if (yychar <= YYMAXTOKEN) yys = yyname[yychar];", + " if (!yys) yys = \"illegal-symbol\";", + " printf(\"%sdebug: state %d, reading %d (%s)\\n\",", + " YYPREFIX, YYFINAL, yychar, yys);", + " }", + "#endif", + " }", + " if (yychar == 0) goto yyaccept;", + " goto yyloop;", + " }", + " if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&", + " yyn <= YYTABLESIZE && yycheck[yyn] == yystate)", + " yystate = yytable[yyn];", + " else", + " yystate = yydgoto[yym];", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: after reduction, shifting from state %d \\", + "to state %d\\n\", YYPREFIX, *yyssp, yystate);", + "#endif", + " if (yyssp >= yyss + yystacksize - 1)", + " {", + " goto yyoverflow;", + " }", + " *++yyssp = yystate;", + " *++yyvsp = yyval;", + " goto yyloop;", + "yyoverflow:", + " yyerror(\"yacc stack overflow\");", + "yyabort:", + " return (1);", + "yyaccept:", + " return (0);", + "}", + 0 +}; + + +write_section(section) +char *section[]; +{ + register int c; + register int i; + register char *s; + register FILE *f; + + f = code_file; + for (i = 0; s = section[i]; ++i) + { + ++outline; + while (c = *s) + { + putc(c, f); + ++s; + } + putc('\n', f); + } +} diff --git a/usr.bin/yacc/symtab.c b/usr.bin/yacc/symtab.c new file mode 100644 index 0000000..0c5f55c --- /dev/null +++ b/usr.bin/yacc/symtab.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)symtab.c 5.3 (Berkeley) 6/1/90"; +#endif /* not lint */ + +#include "defs.h" + +/* TABLE_SIZE is the number of entries in the symbol table. */ +/* TABLE_SIZE must be a power of two. */ + +#define TABLE_SIZE 1024 + + +bucket **symbol_table; +bucket *first_symbol; +bucket *last_symbol; + + +int +hash(name) +char *name; +{ + register char *s; + register int c, k; + + assert(name && *name); + s = name; + k = *s; + while (c = *++s) + k = (31*k + c) & (TABLE_SIZE - 1); + + return (k); +} + + +bucket * +make_bucket(name) +char *name; +{ + register bucket *bp; + + assert(name); + bp = (bucket *) MALLOC(sizeof(bucket)); + if (bp == 0) no_space(); + bp->link = 0; + bp->next = 0; + bp->name = MALLOC(strlen(name) + 1); + if (bp->name == 0) no_space(); + bp->tag = 0; + bp->value = UNDEFINED; + bp->index = 0; + bp->prec = 0; + bp-> class = UNKNOWN; + bp->assoc = TOKEN; + + if (bp->name == 0) no_space(); + strcpy(bp->name, name); + + return (bp); +} + + +bucket * +lookup(name) +char *name; +{ + register bucket *bp, **bpp; + + bpp = symbol_table + hash(name); + bp = *bpp; + + while (bp) + { + if (strcmp(name, bp->name) == 0) return (bp); + bpp = &bp->link; + bp = *bpp; + } + + *bpp = bp = make_bucket(name); + last_symbol->next = bp; + last_symbol = bp; + + return (bp); +} + + +create_symbol_table() +{ + register int i; + register bucket *bp; + + symbol_table = (bucket **) MALLOC(TABLE_SIZE*sizeof(bucket *)); + if (symbol_table == 0) no_space(); + for (i = 0; i < TABLE_SIZE; i++) + symbol_table[i] = 0; + + bp = make_bucket("error"); + bp->index = 1; + bp->class = TERM; + + first_symbol = bp; + last_symbol = bp; + symbol_table[hash("error")] = bp; +} + + +free_symbol_table() +{ + FREE(symbol_table); + symbol_table = 0; +} + + +free_symbols() +{ + register bucket *p, *q; + + for (p = first_symbol; p; p = q) + { + q = p->next; + FREE(p); + } +} diff --git a/usr.bin/yacc/test/error.output b/usr.bin/yacc/test/error.output new file mode 100644 index 0000000..0c4db62 --- /dev/null +++ b/usr.bin/yacc/test/error.output @@ -0,0 +1,27 @@ + 0 $accept : S $end + + 1 S : error + +state 0 + $accept : . S $end (0) + + error shift 1 + . error + + S goto 2 + + +state 1 + S : error . (1) + + . reduce 1 + + +state 2 + $accept : S . $end (0) + + $end accept + + +2 terminals, 2 nonterminals +2 grammar rules, 3 states diff --git a/usr.bin/yacc/test/error.tab.c b/usr.bin/yacc/test/error.tab.c new file mode 100644 index 0000000..ffc6e37 --- /dev/null +++ b/usr.bin/yacc/test/error.tab.c @@ -0,0 +1,275 @@ +#ifndef lint +static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +#define YYPREFIX "yy" +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, +}; +short yylen[] = { 2, + 1, +}; +short yydefred[] = { 0, + 1, 0, +}; +short yydgoto[] = { 2, +}; +short yysindex[] = { -256, + 0, 0, +}; +short yyrindex[] = { 0, + 0, 0, +}; +short yygindex[] = { 0, +}; +#define YYTABLESIZE 0 +short yytable[] = { 1, +}; +short yycheck[] = { 256, +}; +#define YYFINAL 2 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 0 +#if YYDEBUG +char *yyname[] = { +"end-of-file", +}; +char *yyrule[] = { +"$accept : S", +"S : error", +}; +#endif +#ifndef YYSTYPE +typedef int YYSTYPE; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#line 4 "error.y" +main(){printf("yyparse() = %d\n",yyparse());} +yylex(){return-1;} +yyerror(s)char*s;{printf("%s\n",s);} +#line 80 "error.tab.c" +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/usr.bin/yacc/test/error.tab.h b/usr.bin/yacc/test/error.tab.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/usr.bin/yacc/test/error.tab.h diff --git a/usr.bin/yacc/test/error.y b/usr.bin/yacc/test/error.y new file mode 100644 index 0000000..41148ea --- /dev/null +++ b/usr.bin/yacc/test/error.y @@ -0,0 +1,6 @@ +%% +S: error +%% +main(){printf("yyparse() = %d\n",yyparse());} +yylex(){return-1;} +yyerror(s)char*s;{printf("%s\n",s);} diff --git a/usr.bin/yacc/test/ftp.output b/usr.bin/yacc/test/ftp.output new file mode 100644 index 0000000..f1ab4b2 --- /dev/null +++ b/usr.bin/yacc/test/ftp.output @@ -0,0 +1,1625 @@ + 0 $accept : cmd_list $end + + 1 cmd_list : + 2 | cmd_list cmd + 3 | cmd_list rcmd + + 4 cmd : USER SP username CRLF + 5 | PASS SP password CRLF + 6 | PORT SP host_port CRLF + 7 | PASV CRLF + 8 | TYPE SP type_code CRLF + 9 | STRU SP struct_code CRLF + 10 | MODE SP mode_code CRLF + 11 | ALLO SP NUMBER CRLF + 12 | ALLO SP NUMBER SP R SP NUMBER CRLF + 13 | RETR check_login SP pathname CRLF + 14 | STOR check_login SP pathname CRLF + 15 | APPE check_login SP pathname CRLF + 16 | NLST check_login CRLF + 17 | NLST check_login SP STRING CRLF + 18 | LIST check_login CRLF + 19 | LIST check_login SP pathname CRLF + 20 | STAT check_login SP pathname CRLF + 21 | STAT CRLF + 22 | DELE check_login SP pathname CRLF + 23 | RNTO SP pathname CRLF + 24 | ABOR CRLF + 25 | CWD check_login CRLF + 26 | CWD check_login SP pathname CRLF + 27 | HELP CRLF + 28 | HELP SP STRING CRLF + 29 | NOOP CRLF + 30 | MKD check_login SP pathname CRLF + 31 | RMD check_login SP pathname CRLF + 32 | PWD check_login CRLF + 33 | CDUP check_login CRLF + 34 | SITE SP HELP CRLF + 35 | SITE SP HELP SP STRING CRLF + 36 | SITE SP UMASK check_login CRLF + 37 | SITE SP UMASK check_login SP octal_number CRLF + 38 | SITE SP CHMOD check_login SP octal_number SP pathname CRLF + 39 | SITE SP IDLE CRLF + 40 | SITE SP IDLE SP NUMBER CRLF + 41 | STOU check_login SP pathname CRLF + 42 | SYST CRLF + 43 | SIZE check_login SP pathname CRLF + 44 | MDTM check_login SP pathname CRLF + 45 | QUIT CRLF + 46 | error CRLF + + 47 rcmd : RNFR check_login SP pathname CRLF + + 48 username : STRING + + 49 password : + 50 | STRING + + 51 byte_size : NUMBER + + 52 host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER + + 53 form_code : N + 54 | T + 55 | C + + 56 type_code : A + 57 | A SP form_code + 58 | E + 59 | E SP form_code + 60 | I + 61 | L + 62 | L SP byte_size + 63 | L byte_size + + 64 struct_code : F + 65 | R + 66 | P + + 67 mode_code : S + 68 | B + 69 | C + + 70 pathname : pathstring + + 71 pathstring : STRING + + 72 octal_number : NUMBER + + 73 check_login : + +state 0 + $accept : . cmd_list $end (0) + cmd_list : . (1) + + . reduce 1 + + cmd_list goto 1 + + +state 1 + $accept : cmd_list . $end (0) + cmd_list : cmd_list . cmd (2) + cmd_list : cmd_list . rcmd (3) + + $end accept + error shift 2 + USER shift 3 + PASS shift 4 + QUIT shift 5 + PORT shift 6 + PASV shift 7 + TYPE shift 8 + STRU shift 9 + MODE shift 10 + RETR shift 11 + STOR shift 12 + APPE shift 13 + ALLO shift 14 + RNFR shift 15 + RNTO shift 16 + ABOR shift 17 + DELE shift 18 + CWD shift 19 + LIST shift 20 + NLST shift 21 + SITE shift 22 + STAT shift 23 + HELP shift 24 + NOOP shift 25 + MKD shift 26 + RMD shift 27 + PWD shift 28 + CDUP shift 29 + STOU shift 30 + SYST shift 31 + SIZE shift 32 + MDTM shift 33 + . error + + cmd goto 34 + rcmd goto 35 + + +state 2 + cmd : error . CRLF (46) + + CRLF shift 36 + . error + + +state 3 + cmd : USER . SP username CRLF (4) + + SP shift 37 + . error + + +state 4 + cmd : PASS . SP password CRLF (5) + + SP shift 38 + . error + + +state 5 + cmd : QUIT . CRLF (45) + + CRLF shift 39 + . error + + +state 6 + cmd : PORT . SP host_port CRLF (6) + + SP shift 40 + . error + + +state 7 + cmd : PASV . CRLF (7) + + CRLF shift 41 + . error + + +state 8 + cmd : TYPE . SP type_code CRLF (8) + + SP shift 42 + . error + + +state 9 + cmd : STRU . SP struct_code CRLF (9) + + SP shift 43 + . error + + +state 10 + cmd : MODE . SP mode_code CRLF (10) + + SP shift 44 + . error + + +state 11 + cmd : RETR . check_login SP pathname CRLF (13) + check_login : . (73) + + . reduce 73 + + check_login goto 45 + + +state 12 + cmd : STOR . check_login SP pathname CRLF (14) + check_login : . (73) + + . reduce 73 + + check_login goto 46 + + +state 13 + cmd : APPE . check_login SP pathname CRLF (15) + check_login : . (73) + + . reduce 73 + + check_login goto 47 + + +state 14 + cmd : ALLO . SP NUMBER CRLF (11) + cmd : ALLO . SP NUMBER SP R SP NUMBER CRLF (12) + + SP shift 48 + . error + + +state 15 + rcmd : RNFR . check_login SP pathname CRLF (47) + check_login : . (73) + + . reduce 73 + + check_login goto 49 + + +state 16 + cmd : RNTO . SP pathname CRLF (23) + + SP shift 50 + . error + + +state 17 + cmd : ABOR . CRLF (24) + + CRLF shift 51 + . error + + +state 18 + cmd : DELE . check_login SP pathname CRLF (22) + check_login : . (73) + + . reduce 73 + + check_login goto 52 + + +state 19 + cmd : CWD . check_login CRLF (25) + cmd : CWD . check_login SP pathname CRLF (26) + check_login : . (73) + + . reduce 73 + + check_login goto 53 + + +state 20 + cmd : LIST . check_login CRLF (18) + cmd : LIST . check_login SP pathname CRLF (19) + check_login : . (73) + + . reduce 73 + + check_login goto 54 + + +state 21 + cmd : NLST . check_login CRLF (16) + cmd : NLST . check_login SP STRING CRLF (17) + check_login : . (73) + + . reduce 73 + + check_login goto 55 + + +state 22 + cmd : SITE . SP HELP CRLF (34) + cmd : SITE . SP HELP SP STRING CRLF (35) + cmd : SITE . SP UMASK check_login CRLF (36) + cmd : SITE . SP UMASK check_login SP octal_number CRLF (37) + cmd : SITE . SP CHMOD check_login SP octal_number SP pathname CRLF (38) + cmd : SITE . SP IDLE CRLF (39) + cmd : SITE . SP IDLE SP NUMBER CRLF (40) + + SP shift 56 + . error + + +state 23 + cmd : STAT . check_login SP pathname CRLF (20) + cmd : STAT . CRLF (21) + check_login : . (73) + + CRLF shift 57 + SP reduce 73 + + check_login goto 58 + + +state 24 + cmd : HELP . CRLF (27) + cmd : HELP . SP STRING CRLF (28) + + SP shift 59 + CRLF shift 60 + . error + + +state 25 + cmd : NOOP . CRLF (29) + + CRLF shift 61 + . error + + +state 26 + cmd : MKD . check_login SP pathname CRLF (30) + check_login : . (73) + + . reduce 73 + + check_login goto 62 + + +state 27 + cmd : RMD . check_login SP pathname CRLF (31) + check_login : . (73) + + . reduce 73 + + check_login goto 63 + + +state 28 + cmd : PWD . check_login CRLF (32) + check_login : . (73) + + . reduce 73 + + check_login goto 64 + + +state 29 + cmd : CDUP . check_login CRLF (33) + check_login : . (73) + + . reduce 73 + + check_login goto 65 + + +state 30 + cmd : STOU . check_login SP pathname CRLF (41) + check_login : . (73) + + . reduce 73 + + check_login goto 66 + + +state 31 + cmd : SYST . CRLF (42) + + CRLF shift 67 + . error + + +state 32 + cmd : SIZE . check_login SP pathname CRLF (43) + check_login : . (73) + + . reduce 73 + + check_login goto 68 + + +state 33 + cmd : MDTM . check_login SP pathname CRLF (44) + check_login : . (73) + + . reduce 73 + + check_login goto 69 + + +state 34 + cmd_list : cmd_list cmd . (2) + + . reduce 2 + + +state 35 + cmd_list : cmd_list rcmd . (3) + + . reduce 3 + + +state 36 + cmd : error CRLF . (46) + + . reduce 46 + + +state 37 + cmd : USER SP . username CRLF (4) + + STRING shift 70 + . error + + username goto 71 + + +state 38 + cmd : PASS SP . password CRLF (5) + password : . (49) + + STRING shift 72 + CRLF reduce 49 + + password goto 73 + + +state 39 + cmd : QUIT CRLF . (45) + + . reduce 45 + + +state 40 + cmd : PORT SP . host_port CRLF (6) + + NUMBER shift 74 + . error + + host_port goto 75 + + +state 41 + cmd : PASV CRLF . (7) + + . reduce 7 + + +state 42 + cmd : TYPE SP . type_code CRLF (8) + + A shift 76 + E shift 77 + I shift 78 + L shift 79 + . error + + type_code goto 80 + + +state 43 + cmd : STRU SP . struct_code CRLF (9) + + F shift 81 + P shift 82 + R shift 83 + . error + + struct_code goto 84 + + +state 44 + cmd : MODE SP . mode_code CRLF (10) + + B shift 85 + C shift 86 + S shift 87 + . error + + mode_code goto 88 + + +state 45 + cmd : RETR check_login . SP pathname CRLF (13) + + SP shift 89 + . error + + +state 46 + cmd : STOR check_login . SP pathname CRLF (14) + + SP shift 90 + . error + + +state 47 + cmd : APPE check_login . SP pathname CRLF (15) + + SP shift 91 + . error + + +state 48 + cmd : ALLO SP . NUMBER CRLF (11) + cmd : ALLO SP . NUMBER SP R SP NUMBER CRLF (12) + + NUMBER shift 92 + . error + + +state 49 + rcmd : RNFR check_login . SP pathname CRLF (47) + + SP shift 93 + . error + + +state 50 + cmd : RNTO SP . pathname CRLF (23) + + STRING shift 94 + . error + + pathname goto 95 + pathstring goto 96 + + +state 51 + cmd : ABOR CRLF . (24) + + . reduce 24 + + +state 52 + cmd : DELE check_login . SP pathname CRLF (22) + + SP shift 97 + . error + + +state 53 + cmd : CWD check_login . CRLF (25) + cmd : CWD check_login . SP pathname CRLF (26) + + SP shift 98 + CRLF shift 99 + . error + + +state 54 + cmd : LIST check_login . CRLF (18) + cmd : LIST check_login . SP pathname CRLF (19) + + SP shift 100 + CRLF shift 101 + . error + + +state 55 + cmd : NLST check_login . CRLF (16) + cmd : NLST check_login . SP STRING CRLF (17) + + SP shift 102 + CRLF shift 103 + . error + + +state 56 + cmd : SITE SP . HELP CRLF (34) + cmd : SITE SP . HELP SP STRING CRLF (35) + cmd : SITE SP . UMASK check_login CRLF (36) + cmd : SITE SP . UMASK check_login SP octal_number CRLF (37) + cmd : SITE SP . CHMOD check_login SP octal_number SP pathname CRLF (38) + cmd : SITE SP . IDLE CRLF (39) + cmd : SITE SP . IDLE SP NUMBER CRLF (40) + + HELP shift 104 + UMASK shift 105 + IDLE shift 106 + CHMOD shift 107 + . error + + +state 57 + cmd : STAT CRLF . (21) + + . reduce 21 + + +state 58 + cmd : STAT check_login . SP pathname CRLF (20) + + SP shift 108 + . error + + +state 59 + cmd : HELP SP . STRING CRLF (28) + + STRING shift 109 + . error + + +state 60 + cmd : HELP CRLF . (27) + + . reduce 27 + + +state 61 + cmd : NOOP CRLF . (29) + + . reduce 29 + + +state 62 + cmd : MKD check_login . SP pathname CRLF (30) + + SP shift 110 + . error + + +state 63 + cmd : RMD check_login . SP pathname CRLF (31) + + SP shift 111 + . error + + +state 64 + cmd : PWD check_login . CRLF (32) + + CRLF shift 112 + . error + + +state 65 + cmd : CDUP check_login . CRLF (33) + + CRLF shift 113 + . error + + +state 66 + cmd : STOU check_login . SP pathname CRLF (41) + + SP shift 114 + . error + + +state 67 + cmd : SYST CRLF . (42) + + . reduce 42 + + +state 68 + cmd : SIZE check_login . SP pathname CRLF (43) + + SP shift 115 + . error + + +state 69 + cmd : MDTM check_login . SP pathname CRLF (44) + + SP shift 116 + . error + + +state 70 + username : STRING . (48) + + . reduce 48 + + +state 71 + cmd : USER SP username . CRLF (4) + + CRLF shift 117 + . error + + +state 72 + password : STRING . (50) + + . reduce 50 + + +state 73 + cmd : PASS SP password . CRLF (5) + + CRLF shift 118 + . error + + +state 74 + host_port : NUMBER . COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER (52) + + COMMA shift 119 + . error + + +state 75 + cmd : PORT SP host_port . CRLF (6) + + CRLF shift 120 + . error + + +state 76 + type_code : A . (56) + type_code : A . SP form_code (57) + + SP shift 121 + CRLF reduce 56 + + +state 77 + type_code : E . (58) + type_code : E . SP form_code (59) + + SP shift 122 + CRLF reduce 58 + + +state 78 + type_code : I . (60) + + . reduce 60 + + +state 79 + type_code : L . (61) + type_code : L . SP byte_size (62) + type_code : L . byte_size (63) + + SP shift 123 + NUMBER shift 124 + CRLF reduce 61 + + byte_size goto 125 + + +state 80 + cmd : TYPE SP type_code . CRLF (8) + + CRLF shift 126 + . error + + +state 81 + struct_code : F . (64) + + . reduce 64 + + +state 82 + struct_code : P . (66) + + . reduce 66 + + +state 83 + struct_code : R . (65) + + . reduce 65 + + +state 84 + cmd : STRU SP struct_code . CRLF (9) + + CRLF shift 127 + . error + + +state 85 + mode_code : B . (68) + + . reduce 68 + + +state 86 + mode_code : C . (69) + + . reduce 69 + + +state 87 + mode_code : S . (67) + + . reduce 67 + + +state 88 + cmd : MODE SP mode_code . CRLF (10) + + CRLF shift 128 + . error + + +state 89 + cmd : RETR check_login SP . pathname CRLF (13) + + STRING shift 94 + . error + + pathname goto 129 + pathstring goto 96 + + +state 90 + cmd : STOR check_login SP . pathname CRLF (14) + + STRING shift 94 + . error + + pathname goto 130 + pathstring goto 96 + + +state 91 + cmd : APPE check_login SP . pathname CRLF (15) + + STRING shift 94 + . error + + pathname goto 131 + pathstring goto 96 + + +state 92 + cmd : ALLO SP NUMBER . CRLF (11) + cmd : ALLO SP NUMBER . SP R SP NUMBER CRLF (12) + + SP shift 132 + CRLF shift 133 + . error + + +state 93 + rcmd : RNFR check_login SP . pathname CRLF (47) + + STRING shift 94 + . error + + pathname goto 134 + pathstring goto 96 + + +state 94 + pathstring : STRING . (71) + + . reduce 71 + + +state 95 + cmd : RNTO SP pathname . CRLF (23) + + CRLF shift 135 + . error + + +state 96 + pathname : pathstring . (70) + + . reduce 70 + + +state 97 + cmd : DELE check_login SP . pathname CRLF (22) + + STRING shift 94 + . error + + pathname goto 136 + pathstring goto 96 + + +state 98 + cmd : CWD check_login SP . pathname CRLF (26) + + STRING shift 94 + . error + + pathname goto 137 + pathstring goto 96 + + +state 99 + cmd : CWD check_login CRLF . (25) + + . reduce 25 + + +state 100 + cmd : LIST check_login SP . pathname CRLF (19) + + STRING shift 94 + . error + + pathname goto 138 + pathstring goto 96 + + +state 101 + cmd : LIST check_login CRLF . (18) + + . reduce 18 + + +state 102 + cmd : NLST check_login SP . STRING CRLF (17) + + STRING shift 139 + . error + + +state 103 + cmd : NLST check_login CRLF . (16) + + . reduce 16 + + +state 104 + cmd : SITE SP HELP . CRLF (34) + cmd : SITE SP HELP . SP STRING CRLF (35) + + SP shift 140 + CRLF shift 141 + . error + + +state 105 + cmd : SITE SP UMASK . check_login CRLF (36) + cmd : SITE SP UMASK . check_login SP octal_number CRLF (37) + check_login : . (73) + + . reduce 73 + + check_login goto 142 + + +state 106 + cmd : SITE SP IDLE . CRLF (39) + cmd : SITE SP IDLE . SP NUMBER CRLF (40) + + SP shift 143 + CRLF shift 144 + . error + + +state 107 + cmd : SITE SP CHMOD . check_login SP octal_number SP pathname CRLF (38) + check_login : . (73) + + . reduce 73 + + check_login goto 145 + + +state 108 + cmd : STAT check_login SP . pathname CRLF (20) + + STRING shift 94 + . error + + pathname goto 146 + pathstring goto 96 + + +state 109 + cmd : HELP SP STRING . CRLF (28) + + CRLF shift 147 + . error + + +state 110 + cmd : MKD check_login SP . pathname CRLF (30) + + STRING shift 94 + . error + + pathname goto 148 + pathstring goto 96 + + +state 111 + cmd : RMD check_login SP . pathname CRLF (31) + + STRING shift 94 + . error + + pathname goto 149 + pathstring goto 96 + + +state 112 + cmd : PWD check_login CRLF . (32) + + . reduce 32 + + +state 113 + cmd : CDUP check_login CRLF . (33) + + . reduce 33 + + +state 114 + cmd : STOU check_login SP . pathname CRLF (41) + + STRING shift 94 + . error + + pathname goto 150 + pathstring goto 96 + + +state 115 + cmd : SIZE check_login SP . pathname CRLF (43) + + STRING shift 94 + . error + + pathname goto 151 + pathstring goto 96 + + +state 116 + cmd : MDTM check_login SP . pathname CRLF (44) + + STRING shift 94 + . error + + pathname goto 152 + pathstring goto 96 + + +state 117 + cmd : USER SP username CRLF . (4) + + . reduce 4 + + +state 118 + cmd : PASS SP password CRLF . (5) + + . reduce 5 + + +state 119 + host_port : NUMBER COMMA . NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER (52) + + NUMBER shift 153 + . error + + +state 120 + cmd : PORT SP host_port CRLF . (6) + + . reduce 6 + + +state 121 + type_code : A SP . form_code (57) + + C shift 154 + N shift 155 + T shift 156 + . error + + form_code goto 157 + + +state 122 + type_code : E SP . form_code (59) + + C shift 154 + N shift 155 + T shift 156 + . error + + form_code goto 158 + + +state 123 + type_code : L SP . byte_size (62) + + NUMBER shift 124 + . error + + byte_size goto 159 + + +state 124 + byte_size : NUMBER . (51) + + . reduce 51 + + +state 125 + type_code : L byte_size . (63) + + . reduce 63 + + +state 126 + cmd : TYPE SP type_code CRLF . (8) + + . reduce 8 + + +state 127 + cmd : STRU SP struct_code CRLF . (9) + + . reduce 9 + + +state 128 + cmd : MODE SP mode_code CRLF . (10) + + . reduce 10 + + +state 129 + cmd : RETR check_login SP pathname . CRLF (13) + + CRLF shift 160 + . error + + +state 130 + cmd : STOR check_login SP pathname . CRLF (14) + + CRLF shift 161 + . error + + +state 131 + cmd : APPE check_login SP pathname . CRLF (15) + + CRLF shift 162 + . error + + +state 132 + cmd : ALLO SP NUMBER SP . R SP NUMBER CRLF (12) + + R shift 163 + . error + + +state 133 + cmd : ALLO SP NUMBER CRLF . (11) + + . reduce 11 + + +state 134 + rcmd : RNFR check_login SP pathname . CRLF (47) + + CRLF shift 164 + . error + + +state 135 + cmd : RNTO SP pathname CRLF . (23) + + . reduce 23 + + +state 136 + cmd : DELE check_login SP pathname . CRLF (22) + + CRLF shift 165 + . error + + +state 137 + cmd : CWD check_login SP pathname . CRLF (26) + + CRLF shift 166 + . error + + +state 138 + cmd : LIST check_login SP pathname . CRLF (19) + + CRLF shift 167 + . error + + +state 139 + cmd : NLST check_login SP STRING . CRLF (17) + + CRLF shift 168 + . error + + +state 140 + cmd : SITE SP HELP SP . STRING CRLF (35) + + STRING shift 169 + . error + + +state 141 + cmd : SITE SP HELP CRLF . (34) + + . reduce 34 + + +state 142 + cmd : SITE SP UMASK check_login . CRLF (36) + cmd : SITE SP UMASK check_login . SP octal_number CRLF (37) + + SP shift 170 + CRLF shift 171 + . error + + +state 143 + cmd : SITE SP IDLE SP . NUMBER CRLF (40) + + NUMBER shift 172 + . error + + +state 144 + cmd : SITE SP IDLE CRLF . (39) + + . reduce 39 + + +state 145 + cmd : SITE SP CHMOD check_login . SP octal_number SP pathname CRLF (38) + + SP shift 173 + . error + + +state 146 + cmd : STAT check_login SP pathname . CRLF (20) + + CRLF shift 174 + . error + + +state 147 + cmd : HELP SP STRING CRLF . (28) + + . reduce 28 + + +state 148 + cmd : MKD check_login SP pathname . CRLF (30) + + CRLF shift 175 + . error + + +state 149 + cmd : RMD check_login SP pathname . CRLF (31) + + CRLF shift 176 + . error + + +state 150 + cmd : STOU check_login SP pathname . CRLF (41) + + CRLF shift 177 + . error + + +state 151 + cmd : SIZE check_login SP pathname . CRLF (43) + + CRLF shift 178 + . error + + +state 152 + cmd : MDTM check_login SP pathname . CRLF (44) + + CRLF shift 179 + . error + + +state 153 + host_port : NUMBER COMMA NUMBER . COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER (52) + + COMMA shift 180 + . error + + +state 154 + form_code : C . (55) + + . reduce 55 + + +state 155 + form_code : N . (53) + + . reduce 53 + + +state 156 + form_code : T . (54) + + . reduce 54 + + +state 157 + type_code : A SP form_code . (57) + + . reduce 57 + + +state 158 + type_code : E SP form_code . (59) + + . reduce 59 + + +state 159 + type_code : L SP byte_size . (62) + + . reduce 62 + + +state 160 + cmd : RETR check_login SP pathname CRLF . (13) + + . reduce 13 + + +state 161 + cmd : STOR check_login SP pathname CRLF . (14) + + . reduce 14 + + +state 162 + cmd : APPE check_login SP pathname CRLF . (15) + + . reduce 15 + + +state 163 + cmd : ALLO SP NUMBER SP R . SP NUMBER CRLF (12) + + SP shift 181 + . error + + +state 164 + rcmd : RNFR check_login SP pathname CRLF . (47) + + . reduce 47 + + +state 165 + cmd : DELE check_login SP pathname CRLF . (22) + + . reduce 22 + + +state 166 + cmd : CWD check_login SP pathname CRLF . (26) + + . reduce 26 + + +state 167 + cmd : LIST check_login SP pathname CRLF . (19) + + . reduce 19 + + +state 168 + cmd : NLST check_login SP STRING CRLF . (17) + + . reduce 17 + + +state 169 + cmd : SITE SP HELP SP STRING . CRLF (35) + + CRLF shift 182 + . error + + +state 170 + cmd : SITE SP UMASK check_login SP . octal_number CRLF (37) + + NUMBER shift 183 + . error + + octal_number goto 184 + + +state 171 + cmd : SITE SP UMASK check_login CRLF . (36) + + . reduce 36 + + +state 172 + cmd : SITE SP IDLE SP NUMBER . CRLF (40) + + CRLF shift 185 + . error + + +state 173 + cmd : SITE SP CHMOD check_login SP . octal_number SP pathname CRLF (38) + + NUMBER shift 183 + . error + + octal_number goto 186 + + +state 174 + cmd : STAT check_login SP pathname CRLF . (20) + + . reduce 20 + + +state 175 + cmd : MKD check_login SP pathname CRLF . (30) + + . reduce 30 + + +state 176 + cmd : RMD check_login SP pathname CRLF . (31) + + . reduce 31 + + +state 177 + cmd : STOU check_login SP pathname CRLF . (41) + + . reduce 41 + + +state 178 + cmd : SIZE check_login SP pathname CRLF . (43) + + . reduce 43 + + +state 179 + cmd : MDTM check_login SP pathname CRLF . (44) + + . reduce 44 + + +state 180 + host_port : NUMBER COMMA NUMBER COMMA . NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER (52) + + NUMBER shift 187 + . error + + +state 181 + cmd : ALLO SP NUMBER SP R SP . NUMBER CRLF (12) + + NUMBER shift 188 + . error + + +state 182 + cmd : SITE SP HELP SP STRING CRLF . (35) + + . reduce 35 + + +state 183 + octal_number : NUMBER . (72) + + . reduce 72 + + +state 184 + cmd : SITE SP UMASK check_login SP octal_number . CRLF (37) + + CRLF shift 189 + . error + + +state 185 + cmd : SITE SP IDLE SP NUMBER CRLF . (40) + + . reduce 40 + + +state 186 + cmd : SITE SP CHMOD check_login SP octal_number . SP pathname CRLF (38) + + SP shift 190 + . error + + +state 187 + host_port : NUMBER COMMA NUMBER COMMA NUMBER . COMMA NUMBER COMMA NUMBER COMMA NUMBER (52) + + COMMA shift 191 + . error + + +state 188 + cmd : ALLO SP NUMBER SP R SP NUMBER . CRLF (12) + + CRLF shift 192 + . error + + +state 189 + cmd : SITE SP UMASK check_login SP octal_number CRLF . (37) + + . reduce 37 + + +state 190 + cmd : SITE SP CHMOD check_login SP octal_number SP . pathname CRLF (38) + + STRING shift 94 + . error + + pathname goto 193 + pathstring goto 96 + + +state 191 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA . NUMBER COMMA NUMBER COMMA NUMBER (52) + + NUMBER shift 194 + . error + + +state 192 + cmd : ALLO SP NUMBER SP R SP NUMBER CRLF . (12) + + . reduce 12 + + +state 193 + cmd : SITE SP CHMOD check_login SP octal_number SP pathname . CRLF (38) + + CRLF shift 195 + . error + + +state 194 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER . COMMA NUMBER COMMA NUMBER (52) + + COMMA shift 196 + . error + + +state 195 + cmd : SITE SP CHMOD check_login SP octal_number SP pathname CRLF . (38) + + . reduce 38 + + +state 196 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA . NUMBER COMMA NUMBER (52) + + NUMBER shift 197 + . error + + +state 197 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER . COMMA NUMBER (52) + + COMMA shift 198 + . error + + +state 198 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA . NUMBER (52) + + NUMBER shift 199 + . error + + +state 199 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER . (52) + + . reduce 52 + + +65 terminals, 16 nonterminals +74 grammar rules, 200 states diff --git a/usr.bin/yacc/test/ftp.tab.c b/usr.bin/yacc/test/ftp.tab.c new file mode 100644 index 0000000..c9794ed --- /dev/null +++ b/usr.bin/yacc/test/ftp.tab.c @@ -0,0 +1,1743 @@ +#ifndef lint +static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +#define YYPREFIX "yy" +#line 26 "ftp.y" + +#ifndef lint +static char sccsid[] = "@(#)ftpcmd.y 5.20.1.1 (Berkeley) 3/2/89"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> + +#include <arpa/ftp.h> + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#include <pwd.h> +#include <setjmp.h> +#include <syslog.h> +#include <sys/stat.h> +#include <time.h> + +extern struct sockaddr_in data_dest; +extern int logged_in; +extern struct passwd *pw; +extern int guest; +extern int logging; +extern int type; +extern int form; +extern int debug; +extern int timeout; +extern int maxtimeout; +extern int pdata; +extern char hostname[], remotehost[]; +extern char proctitle[]; +extern char *globerr; +extern int usedefault; +extern int transflag; +extern char tmpline[]; +char **glob(); + +static int cmd_type; +static int cmd_form; +static int cmd_bytesz; +char cbuf[512]; +char *fromname; + +char *index(); +#line 60 "ftp.tab.c" +#define A 257 +#define B 258 +#define C 259 +#define E 260 +#define F 261 +#define I 262 +#define L 263 +#define N 264 +#define P 265 +#define R 266 +#define S 267 +#define T 268 +#define SP 269 +#define CRLF 270 +#define COMMA 271 +#define STRING 272 +#define NUMBER 273 +#define USER 274 +#define PASS 275 +#define ACCT 276 +#define REIN 277 +#define QUIT 278 +#define PORT 279 +#define PASV 280 +#define TYPE 281 +#define STRU 282 +#define MODE 283 +#define RETR 284 +#define STOR 285 +#define APPE 286 +#define MLFL 287 +#define MAIL 288 +#define MSND 289 +#define MSOM 290 +#define MSAM 291 +#define MRSQ 292 +#define MRCP 293 +#define ALLO 294 +#define REST 295 +#define RNFR 296 +#define RNTO 297 +#define ABOR 298 +#define DELE 299 +#define CWD 300 +#define LIST 301 +#define NLST 302 +#define SITE 303 +#define STAT 304 +#define HELP 305 +#define NOOP 306 +#define MKD 307 +#define RMD 308 +#define PWD 309 +#define CDUP 310 +#define STOU 311 +#define SMNT 312 +#define SYST 313 +#define SIZE 314 +#define MDTM 315 +#define UMASK 316 +#define IDLE 317 +#define CHMOD 318 +#define LEXERR 319 +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 3, 4, 4, + 12, 5, 13, 13, 13, 6, 6, 6, 6, 6, + 6, 6, 6, 7, 7, 7, 8, 8, 8, 10, + 14, 11, 9, +}; +short yylen[] = { 2, + 0, 2, 2, 4, 4, 4, 2, 4, 4, 4, + 4, 8, 5, 5, 5, 3, 5, 3, 5, 5, + 2, 5, 4, 2, 3, 5, 2, 4, 2, 5, + 5, 3, 3, 4, 6, 5, 7, 9, 4, 6, + 5, 2, 5, 5, 2, 2, 5, 1, 0, 1, + 1, 11, 1, 1, 1, 1, 3, 1, 3, 1, + 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, +}; +short yydefred[] = { 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 73, 73, 73, 0, 73, 0, 0, 73, 73, 73, + 73, 0, 0, 0, 0, 73, 73, 73, 73, 73, + 0, 73, 73, 2, 3, 46, 0, 0, 45, 0, + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 0, 0, 0, 0, 0, 21, 0, 0, 27, + 29, 0, 0, 0, 0, 0, 42, 0, 0, 48, + 0, 50, 0, 0, 0, 0, 0, 60, 0, 0, + 64, 66, 65, 0, 68, 69, 67, 0, 0, 0, + 0, 0, 0, 71, 0, 70, 0, 0, 25, 0, + 18, 0, 16, 0, 73, 0, 73, 0, 0, 0, + 0, 32, 33, 0, 0, 0, 4, 5, 0, 6, + 0, 0, 0, 51, 63, 8, 9, 10, 0, 0, + 0, 0, 11, 0, 23, 0, 0, 0, 0, 0, + 34, 0, 0, 39, 0, 0, 28, 0, 0, 0, + 0, 0, 0, 55, 53, 54, 57, 59, 62, 13, + 14, 15, 0, 47, 22, 26, 19, 17, 0, 0, + 36, 0, 0, 20, 30, 31, 41, 43, 44, 0, + 0, 35, 72, 0, 40, 0, 0, 0, 37, 0, + 0, 12, 0, 0, 38, 0, 0, 0, 52, +}; +short yydgoto[] = { 1, + 34, 35, 71, 73, 75, 80, 84, 88, 45, 95, + 184, 125, 157, 96, +}; +short yysindex[] = { 0, + -224, -247, -239, -236, -232, -222, -204, -200, -181, -177, + 0, 0, 0, -166, 0, -161, -199, 0, 0, 0, + 0, -160, -159, -264, -158, 0, 0, 0, 0, 0, + -157, 0, 0, 0, 0, 0, -167, -162, 0, -156, + 0, -250, -198, -165, -155, -154, -153, -151, -150, -152, + 0, -145, -252, -229, -217, -302, 0, -144, -146, 0, + 0, -142, -141, -140, -139, -137, 0, -136, -135, 0, + -134, 0, -133, -132, -130, -131, -128, 0, -249, -127, + 0, 0, 0, -126, 0, 0, 0, -125, -152, -152, + -152, -205, -152, 0, -124, 0, -152, -152, 0, -152, + 0, -143, 0, -173, 0, -171, 0, -152, -123, -152, + -152, 0, 0, -152, -152, -152, 0, 0, -138, 0, + -164, -164, -122, 0, 0, 0, 0, 0, -121, -120, + -118, -148, 0, -117, 0, -116, -115, -114, -113, -112, + 0, -163, -111, 0, -110, -109, 0, -107, -106, -105, + -104, -103, -129, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -101, 0, 0, 0, 0, 0, -100, -102, + 0, -98, -102, 0, 0, 0, 0, 0, 0, -99, + -97, 0, 0, -95, 0, -96, -94, -92, 0, -152, + -93, 0, -91, -90, 0, -88, -87, -86, 0, +}; +short yyrindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -83, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -82, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -81, -80, 0, -158, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +short yygindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 16, -89, + -25, 35, 47, 0, +}; +#define YYTABLESIZE 190 +short yytable[] = { 129, + 130, 131, 104, 134, 59, 60, 76, 136, 137, 77, + 138, 78, 79, 105, 106, 107, 98, 99, 146, 123, + 148, 149, 36, 124, 150, 151, 152, 46, 47, 37, + 49, 2, 38, 52, 53, 54, 55, 39, 58, 100, + 101, 62, 63, 64, 65, 66, 40, 68, 69, 3, + 4, 102, 103, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 81, 132, 133, 41, 82, 83, 42, 14, + 51, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 43, 31, 32, + 33, 44, 85, 86, 154, 140, 141, 143, 144, 155, + 193, 87, 48, 156, 70, 170, 171, 50, 56, 72, + 57, 61, 67, 89, 90, 91, 74, 163, 93, 94, + 142, 92, 145, 97, 108, 109, 110, 111, 139, 112, + 113, 114, 115, 116, 153, 117, 118, 121, 119, 120, + 122, 180, 126, 127, 128, 135, 147, 186, 160, 161, + 124, 162, 164, 165, 166, 167, 168, 159, 173, 169, + 174, 172, 175, 176, 177, 178, 179, 181, 158, 182, + 183, 185, 190, 187, 189, 188, 191, 192, 195, 194, + 196, 0, 0, 198, 197, 73, 199, 49, 56, 58, +}; +short yycheck[] = { 89, + 90, 91, 305, 93, 269, 270, 257, 97, 98, 260, + 100, 262, 263, 316, 317, 318, 269, 270, 108, 269, + 110, 111, 270, 273, 114, 115, 116, 12, 13, 269, + 15, 256, 269, 18, 19, 20, 21, 270, 23, 269, + 270, 26, 27, 28, 29, 30, 269, 32, 33, 274, + 275, 269, 270, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 261, 269, 270, 270, 265, 266, 269, 294, + 270, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 269, 313, 314, + 315, 269, 258, 259, 259, 269, 270, 269, 270, 264, + 190, 267, 269, 268, 272, 269, 270, 269, 269, 272, + 270, 270, 270, 269, 269, 269, 273, 266, 269, 272, + 105, 273, 107, 269, 269, 272, 269, 269, 272, 270, + 270, 269, 269, 269, 273, 270, 270, 269, 271, 270, + 269, 271, 270, 270, 270, 270, 270, 173, 270, 270, + 273, 270, 270, 270, 270, 270, 270, 123, 269, 272, + 270, 273, 270, 270, 270, 270, 270, 269, 122, 270, + 273, 270, 269, 273, 270, 273, 271, 270, 270, 273, + 271, -1, -1, 271, 273, 269, 273, 270, 270, 270, +}; +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 319 +#if YYDEBUG +char *yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"A","B","C","E","F","I","L","N", +"P","R","S","T","SP","CRLF","COMMA","STRING","NUMBER","USER","PASS","ACCT", +"REIN","QUIT","PORT","PASV","TYPE","STRU","MODE","RETR","STOR","APPE","MLFL", +"MAIL","MSND","MSOM","MSAM","MRSQ","MRCP","ALLO","REST","RNFR","RNTO","ABOR", +"DELE","CWD","LIST","NLST","SITE","STAT","HELP","NOOP","MKD","RMD","PWD","CDUP", +"STOU","SMNT","SYST","SIZE","MDTM","UMASK","IDLE","CHMOD","LEXERR", +}; +char *yyrule[] = { +"$accept : cmd_list", +"cmd_list :", +"cmd_list : cmd_list cmd", +"cmd_list : cmd_list rcmd", +"cmd : USER SP username CRLF", +"cmd : PASS SP password CRLF", +"cmd : PORT SP host_port CRLF", +"cmd : PASV CRLF", +"cmd : TYPE SP type_code CRLF", +"cmd : STRU SP struct_code CRLF", +"cmd : MODE SP mode_code CRLF", +"cmd : ALLO SP NUMBER CRLF", +"cmd : ALLO SP NUMBER SP R SP NUMBER CRLF", +"cmd : RETR check_login SP pathname CRLF", +"cmd : STOR check_login SP pathname CRLF", +"cmd : APPE check_login SP pathname CRLF", +"cmd : NLST check_login CRLF", +"cmd : NLST check_login SP STRING CRLF", +"cmd : LIST check_login CRLF", +"cmd : LIST check_login SP pathname CRLF", +"cmd : STAT check_login SP pathname CRLF", +"cmd : STAT CRLF", +"cmd : DELE check_login SP pathname CRLF", +"cmd : RNTO SP pathname CRLF", +"cmd : ABOR CRLF", +"cmd : CWD check_login CRLF", +"cmd : CWD check_login SP pathname CRLF", +"cmd : HELP CRLF", +"cmd : HELP SP STRING CRLF", +"cmd : NOOP CRLF", +"cmd : MKD check_login SP pathname CRLF", +"cmd : RMD check_login SP pathname CRLF", +"cmd : PWD check_login CRLF", +"cmd : CDUP check_login CRLF", +"cmd : SITE SP HELP CRLF", +"cmd : SITE SP HELP SP STRING CRLF", +"cmd : SITE SP UMASK check_login CRLF", +"cmd : SITE SP UMASK check_login SP octal_number CRLF", +"cmd : SITE SP CHMOD check_login SP octal_number SP pathname CRLF", +"cmd : SITE SP IDLE CRLF", +"cmd : SITE SP IDLE SP NUMBER CRLF", +"cmd : STOU check_login SP pathname CRLF", +"cmd : SYST CRLF", +"cmd : SIZE check_login SP pathname CRLF", +"cmd : MDTM check_login SP pathname CRLF", +"cmd : QUIT CRLF", +"cmd : error CRLF", +"rcmd : RNFR check_login SP pathname CRLF", +"username : STRING", +"password :", +"password : STRING", +"byte_size : NUMBER", +"host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER", +"form_code : N", +"form_code : T", +"form_code : C", +"type_code : A", +"type_code : A SP form_code", +"type_code : E", +"type_code : E SP form_code", +"type_code : I", +"type_code : L", +"type_code : L SP byte_size", +"type_code : L byte_size", +"struct_code : F", +"struct_code : R", +"struct_code : P", +"mode_code : S", +"mode_code : B", +"mode_code : C", +"pathname : pathstring", +"pathstring : STRING", +"octal_number : NUMBER", +"check_login :", +}; +#endif +#ifndef YYSTYPE +typedef int YYSTYPE; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#line 658 "ftp.y" + +extern jmp_buf errcatch; + +#define CMD 0 /* beginning of command */ +#define ARGS 1 /* expect miscellaneous arguments */ +#define STR1 2 /* expect SP followed by STRING */ +#define STR2 3 /* expect STRING */ +#define OSTR 4 /* optional SP then STRING */ +#define ZSTR1 5 /* SP then optional STRING */ +#define ZSTR2 6 /* optional STRING after SP */ +#define SITECMD 7 /* SITE command */ +#define NSTR 8 /* Number followed by a string */ + +struct tab { + char *name; + short token; + short state; + short implemented; /* 1 if command is implemented */ + char *help; +}; + +struct tab cmdtab[] = { /* In order defined in RFC 765 */ + { "USER", USER, STR1, 1, "<sp> username" }, + { "PASS", PASS, ZSTR1, 1, "<sp> password" }, + { "ACCT", ACCT, STR1, 0, "(specify account)" }, + { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, + { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, + { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, + { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" }, + { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, + { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" }, + { "STRU", STRU, ARGS, 1, "(specify file structure)" }, + { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, + { "RETR", RETR, STR1, 1, "<sp> file-name" }, + { "STOR", STOR, STR1, 1, "<sp> file-name" }, + { "APPE", APPE, STR1, 1, "<sp> file-name" }, + { "MLFL", MLFL, OSTR, 0, "(mail file)" }, + { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, + { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, + { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, + { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, + { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, + { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, + { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, + { "REST", REST, ARGS, 0, "(restart command)" }, + { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, + { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, + { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, + { "DELE", DELE, STR1, 1, "<sp> file-name" }, + { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, + { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, + { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, + { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, + { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, + { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, + { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, + { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, + { "NOOP", NOOP, ARGS, 1, "" }, + { "MKD", MKD, STR1, 1, "<sp> path-name" }, + { "XMKD", MKD, STR1, 1, "<sp> path-name" }, + { "RMD", RMD, STR1, 1, "<sp> path-name" }, + { "XRMD", RMD, STR1, 1, "<sp> path-name" }, + { "PWD", PWD, ARGS, 1, "(return current directory)" }, + { "XPWD", PWD, ARGS, 1, "(return current directory)" }, + { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, + { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, + { "STOU", STOU, STR1, 1, "<sp> file-name" }, + { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, + { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, + { NULL, 0, 0, 0, 0 } +}; + +struct tab sitetab[] = { + { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, + { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, + { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, + { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, + { NULL, 0, 0, 0, 0 } +}; + +struct tab * +lookup(p, cmd) + register struct tab *p; + char *cmd; +{ + + for (; p->name != NULL; p++) + if (strcmp(cmd, p->name) == 0) + return (p); + return (0); +} + +#include <arpa/telnet.h> + +/* + * getline - a hacked up version of fgets to ignore TELNET escape codes. + */ +char * +getline(s, n, iop) + char *s; + register FILE *iop; +{ + register c; + register char *cs; + + cs = s; +/* tmpline may contain saved command from urgent mode interruption */ + for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { + *cs++ = tmpline[c]; + if (tmpline[c] == '\n') { + *cs++ = '\0'; + if (debug) + syslog(LOG_DEBUG, "command: %s", s); + tmpline[0] = '\0'; + return(s); + } + if (c == 0) + tmpline[0] = '\0'; + } + while ((c = getc(iop)) != EOF) { + c &= 0377; + if (c == IAC) { + if ((c = getc(iop)) != EOF) { + c &= 0377; + switch (c) { + case WILL: + case WONT: + c = getc(iop); + printf("%c%c%c", IAC, DONT, 0377&c); + (void) fflush(stdout); + continue; + case DO: + case DONT: + c = getc(iop); + printf("%c%c%c", IAC, WONT, 0377&c); + (void) fflush(stdout); + continue; + case IAC: + break; + default: + continue; /* ignore command */ + } + } + } + *cs++ = c; + if (--n <= 0 || c == '\n') + break; + } + if (c == EOF && cs == s) + return (NULL); + *cs++ = '\0'; + if (debug) + syslog(LOG_DEBUG, "command: %s", s); + return (s); +} + +static int +toolong() +{ + time_t now; + extern char *ctime(); + extern time_t time(); + + reply(421, + "Timeout (%d seconds): closing control connection.", timeout); + (void) time(&now); + if (logging) { + syslog(LOG_INFO, + "User %s timed out after %d seconds at %s", + (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now)); + } + dologout(1); +} + +yylex() +{ + static int cpos, state; + register char *cp, *cp2; + register struct tab *p; + int n; + char c, *strpbrk(); + char *copy(); + + for (;;) { + switch (state) { + + case CMD: + (void) signal(SIGALRM, toolong); + (void) alarm((unsigned) timeout); + if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { + reply(221, "You could at least say goodbye."); + dologout(0); + } + (void) alarm(0); +#ifdef SETPROCTITLE + if (strncasecmp(cbuf, "PASS", 4) != NULL) + setproctitle("%s: %s", proctitle, cbuf); +#endif /* SETPROCTITLE */ + if ((cp = index(cbuf, '\r'))) { + *cp++ = '\n'; + *cp = '\0'; + } + if ((cp = strpbrk(cbuf, " \n"))) + cpos = cp - cbuf; + if (cpos == 0) + cpos = 4; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + upper(cbuf); + p = lookup(cmdtab, cbuf); + cbuf[cpos] = c; + if (p != 0) { + if (p->implemented == 0) { + nack(p->name); + longjmp(errcatch,0); + /* NOTREACHED */ + } + state = p->state; + *(char **)&yylval = p->name; + return (p->token); + } + break; + + case SITECMD: + if (cbuf[cpos] == ' ') { + cpos++; + return (SP); + } + cp = &cbuf[cpos]; + if ((cp2 = strpbrk(cp, " \n"))) + cpos = cp2 - cbuf; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + upper(cp); + p = lookup(sitetab, cp); + cbuf[cpos] = c; + if (p != 0) { + if (p->implemented == 0) { + state = CMD; + nack(p->name); + longjmp(errcatch,0); + /* NOTREACHED */ + } + state = p->state; + *(char **)&yylval = p->name; + return (p->token); + } + state = CMD; + break; + + case OSTR: + if (cbuf[cpos] == '\n') { + state = CMD; + return (CRLF); + } + /* FALLTHROUGH */ + + case STR1: + case ZSTR1: + dostr1: + if (cbuf[cpos] == ' ') { + cpos++; + state = state == OSTR ? STR2 : ++state; + return (SP); + } + break; + + case ZSTR2: + if (cbuf[cpos] == '\n') { + state = CMD; + return (CRLF); + } + /* FALLTHROUGH */ + + case STR2: + cp = &cbuf[cpos]; + n = strlen(cp); + cpos += n - 1; + /* + * Make sure the string is nonempty and \n terminated. + */ + if (n > 1 && cbuf[cpos] == '\n') { + cbuf[cpos] = '\0'; + *(char **)&yylval = copy(cp); + cbuf[cpos] = '\n'; + state = ARGS; + return (STRING); + } + break; + + case NSTR: + if (cbuf[cpos] == ' ') { + cpos++; + return (SP); + } + if (isdigit(cbuf[cpos])) { + cp = &cbuf[cpos]; + while (isdigit(cbuf[++cpos])) + ; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + yylval = atoi(cp); + cbuf[cpos] = c; + state = STR1; + return (NUMBER); + } + state = STR1; + goto dostr1; + + case ARGS: + if (isdigit(cbuf[cpos])) { + cp = &cbuf[cpos]; + while (isdigit(cbuf[++cpos])) + ; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + yylval = atoi(cp); + cbuf[cpos] = c; + return (NUMBER); + } + switch (cbuf[cpos++]) { + + case '\n': + state = CMD; + return (CRLF); + + case ' ': + return (SP); + + case ',': + return (COMMA); + + case 'A': + case 'a': + return (A); + + case 'B': + case 'b': + return (B); + + case 'C': + case 'c': + return (C); + + case 'E': + case 'e': + return (E); + + case 'F': + case 'f': + return (F); + + case 'I': + case 'i': + return (I); + + case 'L': + case 'l': + return (L); + + case 'N': + case 'n': + return (N); + + case 'P': + case 'p': + return (P); + + case 'R': + case 'r': + return (R); + + case 'S': + case 's': + return (S); + + case 'T': + case 't': + return (T); + + } + break; + + default: + fatal("Unknown state in scanner."); + } + yyerror((char *) 0); + state = CMD; + longjmp(errcatch,0); + } +} + +upper(s) + register char *s; +{ + while (*s != '\0') { + if (islower(*s)) + *s = toupper(*s); + s++; + } +} + +char * +copy(s) + char *s; +{ + char *p; + extern char *malloc(), *strcpy(); + + p = malloc((unsigned) strlen(s) + 1); + if (p == NULL) + fatal("Ran out of memory."); + (void) strcpy(p, s); + return (p); +} + +help(ctab, s) + struct tab *ctab; + char *s; +{ + register struct tab *c; + register int width, NCMDS; + char *type; + + if (ctab == sitetab) + type = "SITE "; + else + type = ""; + width = 0, NCMDS = 0; + for (c = ctab; c->name != NULL; c++) { + int len = strlen(c->name); + + if (len > width) + width = len; + NCMDS++; + } + width = (width + 8) &~ 7; + if (s == 0) { + register int i, j, w; + int columns, lines; + + lreply(214, "The following %scommands are recognized %s.", + type, "(* =>'s unimplemented)"); + columns = 76 / width; + if (columns == 0) + columns = 1; + lines = (NCMDS + columns - 1) / columns; + for (i = 0; i < lines; i++) { + printf(" "); + for (j = 0; j < columns; j++) { + c = ctab + j * lines + i; + printf("%s%c", c->name, + c->implemented ? ' ' : '*'); + if (c + lines >= &ctab[NCMDS]) + break; + w = strlen(c->name) + 1; + while (w < width) { + putchar(' '); + w++; + } + } + printf("\r\n"); + } + (void) fflush(stdout); + reply(214, "Direct comments to ftp-bugs@%s.", hostname); + return; + } + upper(s); + c = lookup(ctab, s); + if (c == (struct tab *)0) { + reply(502, "Unknown command %s.", s); + return; + } + if (c->implemented) + reply(214, "Syntax: %s%s %s", type, c->name, c->help); + else + reply(214, "%s%-*s\t%s; unimplemented.", type, width, + c->name, c->help); +} + +sizecmd(filename) +char *filename; +{ + switch (type) { + case TYPE_L: + case TYPE_I: { + struct stat stbuf; + if (stat(filename, &stbuf) < 0 || + (stbuf.st_mode&S_IFMT) != S_IFREG) + reply(550, "%s: not a plain file.", filename); + else + reply(213, "%lu", stbuf.st_size); + break;} + case TYPE_A: { + FILE *fin; + register int c, count; + struct stat stbuf; + fin = fopen(filename, "r"); + if (fin == NULL) { + perror_reply(550, filename); + return; + } + if (fstat(fileno(fin), &stbuf) < 0 || + (stbuf.st_mode&S_IFMT) != S_IFREG) { + reply(550, "%s: not a plain file.", filename); + (void) fclose(fin); + return; + } + + count = 0; + while((c=getc(fin)) != EOF) { + if (c == '\n') /* will get expanded to \r\n */ + count++; + count++; + } + (void) fclose(fin); + + reply(213, "%ld", count); + break;} + default: + reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); + } +} +#line 908 "ftp.tab.c" +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 2: +#line 99 "ftp.y" + { + fromname = (char *) 0; + } +break; +case 4: +#line 106 "ftp.y" + { + user((char *) yyvsp[-1]); + free((char *) yyvsp[-1]); + } +break; +case 5: +#line 111 "ftp.y" + { + pass((char *) yyvsp[-1]); + free((char *) yyvsp[-1]); + } +break; +case 6: +#line 116 "ftp.y" + { + usedefault = 0; + if (pdata >= 0) { + (void) close(pdata); + pdata = -1; + } + reply(200, "PORT command successful."); + } +break; +case 7: +#line 125 "ftp.y" + { + passive(); + } +break; +case 8: +#line 129 "ftp.y" + { + switch (cmd_type) { + + case TYPE_A: + if (cmd_form == FORM_N) { + reply(200, "Type set to A."); + type = cmd_type; + form = cmd_form; + } else + reply(504, "Form must be N."); + break; + + case TYPE_E: + reply(504, "Type E not implemented."); + break; + + case TYPE_I: + reply(200, "Type set to I."); + type = cmd_type; + break; + + case TYPE_L: +#if NBBY == 8 + if (cmd_bytesz == 8) { + reply(200, + "Type set to L (byte size 8)."); + type = cmd_type; + } else + reply(504, "Byte size must be 8."); +#else /* NBBY == 8 */ + UNIMPLEMENTED for NBBY != 8 +#endif /* NBBY == 8 */ + } + } +break; +case 9: +#line 164 "ftp.y" + { + switch (yyvsp[-1]) { + + case STRU_F: + reply(200, "STRU F ok."); + break; + + default: + reply(504, "Unimplemented STRU type."); + } + } +break; +case 10: +#line 176 "ftp.y" + { + switch (yyvsp[-1]) { + + case MODE_S: + reply(200, "MODE S ok."); + break; + + default: + reply(502, "Unimplemented MODE type."); + } + } +break; +case 11: +#line 188 "ftp.y" + { + reply(202, "ALLO command ignored."); + } +break; +case 12: +#line 192 "ftp.y" + { + reply(202, "ALLO command ignored."); + } +break; +case 13: +#line 196 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + retrieve((char *) 0, (char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 14: +#line 203 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + store((char *) yyvsp[-1], "w", 0); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 15: +#line 210 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + store((char *) yyvsp[-1], "a", 0); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 16: +#line 217 "ftp.y" + { + if (yyvsp[-1]) + send_file_list("."); + } +break; +case 17: +#line 222 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + send_file_list((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 18: +#line 229 "ftp.y" + { + if (yyvsp[-1]) + retrieve("/bin/ls -lgA", ""); + } +break; +case 19: +#line 234 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + retrieve("/bin/ls -lgA %s", (char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 20: +#line 241 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + statfilecmd((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 21: +#line 248 "ftp.y" + { + statcmd(); + } +break; +case 22: +#line 252 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + delete((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 23: +#line 259 "ftp.y" + { + if (fromname) { + renamecmd(fromname, (char *) yyvsp[-1]); + free(fromname); + fromname = (char *) 0; + } else { + reply(503, "Bad sequence of commands."); + } + free((char *) yyvsp[-1]); + } +break; +case 24: +#line 270 "ftp.y" + { + reply(225, "ABOR command successful."); + } +break; +case 25: +#line 274 "ftp.y" + { + if (yyvsp[-1]) + cwd(pw->pw_dir); + } +break; +case 26: +#line 279 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + cwd((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 27: +#line 286 "ftp.y" + { + help(cmdtab, (char *) 0); + } +break; +case 28: +#line 290 "ftp.y" + { + register char *cp = (char *)yyvsp[-1]; + + if (strncasecmp(cp, "SITE", 4) == 0) { + cp = (char *)yyvsp[-1] + 4; + if (*cp == ' ') + cp++; + if (*cp) + help(sitetab, cp); + else + help(sitetab, (char *) 0); + } else + help(cmdtab, (char *) yyvsp[-1]); + } +break; +case 29: +#line 305 "ftp.y" + { + reply(200, "NOOP command successful."); + } +break; +case 30: +#line 309 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + makedir((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 31: +#line 316 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + removedir((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 32: +#line 323 "ftp.y" + { + if (yyvsp[-1]) + pwd(); + } +break; +case 33: +#line 328 "ftp.y" + { + if (yyvsp[-1]) + cwd(".."); + } +break; +case 34: +#line 333 "ftp.y" + { + help(sitetab, (char *) 0); + } +break; +case 35: +#line 337 "ftp.y" + { + help(sitetab, (char *) yyvsp[-1]); + } +break; +case 36: +#line 341 "ftp.y" + { + int oldmask; + + if (yyvsp[-1]) { + oldmask = umask(0); + (void) umask(oldmask); + reply(200, "Current UMASK is %03o", oldmask); + } + } +break; +case 37: +#line 351 "ftp.y" + { + int oldmask; + + if (yyvsp[-3]) { + if ((yyvsp[-1] == -1) || (yyvsp[-1] > 0777)) { + reply(501, "Bad UMASK value"); + } else { + oldmask = umask(yyvsp[-1]); + reply(200, + "UMASK set to %03o (was %03o)", + yyvsp[-1], oldmask); + } + } + } +break; +case 38: +#line 366 "ftp.y" + { + if (yyvsp[-5] && (yyvsp[-1] != NULL)) { + if (yyvsp[-3] > 0777) + reply(501, + "CHMOD: Mode value must be between 0 and 0777"); + else if (chmod((char *) yyvsp[-1], yyvsp[-3]) < 0) + perror_reply(550, (char *) yyvsp[-1]); + else + reply(200, "CHMOD command successful."); + } + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 39: +#line 380 "ftp.y" + { + reply(200, + "Current IDLE time limit is %d seconds; max %d", + timeout, maxtimeout); + } +break; +case 40: +#line 386 "ftp.y" + { + if (yyvsp[-1] < 30 || yyvsp[-1] > maxtimeout) { + reply(501, + "Maximum IDLE time must be between 30 and %d seconds", + maxtimeout); + } else { + timeout = yyvsp[-1]; + (void) alarm((unsigned) timeout); + reply(200, + "Maximum IDLE time set to %d seconds", + timeout); + } + } +break; +case 41: +#line 400 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + store((char *) yyvsp[-1], "w", 1); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 42: +#line 407 "ftp.y" + { +#ifdef unix +#ifdef BSD + reply(215, "UNIX Type: L%d Version: BSD-%d", + NBBY, BSD); +#else /* BSD */ + reply(215, "UNIX Type: L%d", NBBY); +#endif /* BSD */ +#else /* unix */ + reply(215, "UNKNOWN Type: L%d", NBBY); +#endif /* unix */ + } +break; +case 43: +#line 428 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + sizecmd((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 44: +#line 445 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) { + struct stat stbuf; + if (stat((char *) yyvsp[-1], &stbuf) < 0) + perror_reply(550, "%s", (char *) yyvsp[-1]); + else if ((stbuf.st_mode&S_IFMT) != S_IFREG) { + reply(550, "%s: not a plain file.", + (char *) yyvsp[-1]); + } else { + register struct tm *t; + struct tm *gmtime(); + t = gmtime(&stbuf.st_mtime); + reply(213, + "19%02d%02d%02d%02d%02d%02d", + t->tm_year, t->tm_mon+1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + } + } + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 45: +#line 467 "ftp.y" + { + reply(221, "Goodbye."); + dologout(0); + } +break; +case 46: +#line 472 "ftp.y" + { + yyerrok; + } +break; +case 47: +#line 477 "ftp.y" + { + char *renamefrom(); + + if (yyvsp[-3] && yyvsp[-1]) { + fromname = renamefrom((char *) yyvsp[-1]); + if (fromname == (char *) 0 && yyvsp[-1]) { + free((char *) yyvsp[-1]); + } + } + } +break; +case 49: +#line 493 "ftp.y" + { + *(char **)&(yyval) = ""; + } +break; +case 52: +#line 504 "ftp.y" + { + register char *a, *p; + + a = (char *)&data_dest.sin_addr; + a[0] = yyvsp[-10]; a[1] = yyvsp[-8]; a[2] = yyvsp[-6]; a[3] = yyvsp[-4]; + p = (char *)&data_dest.sin_port; + p[0] = yyvsp[-2]; p[1] = yyvsp[0]; + data_dest.sin_family = AF_INET; + } +break; +case 53: +#line 516 "ftp.y" + { + yyval = FORM_N; + } +break; +case 54: +#line 520 "ftp.y" + { + yyval = FORM_T; + } +break; +case 55: +#line 524 "ftp.y" + { + yyval = FORM_C; + } +break; +case 56: +#line 530 "ftp.y" + { + cmd_type = TYPE_A; + cmd_form = FORM_N; + } +break; +case 57: +#line 535 "ftp.y" + { + cmd_type = TYPE_A; + cmd_form = yyvsp[0]; + } +break; +case 58: +#line 540 "ftp.y" + { + cmd_type = TYPE_E; + cmd_form = FORM_N; + } +break; +case 59: +#line 545 "ftp.y" + { + cmd_type = TYPE_E; + cmd_form = yyvsp[0]; + } +break; +case 60: +#line 550 "ftp.y" + { + cmd_type = TYPE_I; + } +break; +case 61: +#line 554 "ftp.y" + { + cmd_type = TYPE_L; + cmd_bytesz = NBBY; + } +break; +case 62: +#line 559 "ftp.y" + { + cmd_type = TYPE_L; + cmd_bytesz = yyvsp[0]; + } +break; +case 63: +#line 565 "ftp.y" + { + cmd_type = TYPE_L; + cmd_bytesz = yyvsp[0]; + } +break; +case 64: +#line 572 "ftp.y" + { + yyval = STRU_F; + } +break; +case 65: +#line 576 "ftp.y" + { + yyval = STRU_R; + } +break; +case 66: +#line 580 "ftp.y" + { + yyval = STRU_P; + } +break; +case 67: +#line 586 "ftp.y" + { + yyval = MODE_S; + } +break; +case 68: +#line 590 "ftp.y" + { + yyval = MODE_B; + } +break; +case 69: +#line 594 "ftp.y" + { + yyval = MODE_C; + } +break; +case 70: +#line 600 "ftp.y" + { + /* + * Problem: this production is used for all pathname + * processing, but only gives a 550 error reply. + * This is a valid reply in some cases but not in others. + */ + if (logged_in && yyvsp[0] && strncmp((char *) yyvsp[0], "~", 1) == 0) { + *(char **)&(yyval) = *glob((char *) yyvsp[0]); + if (globerr != NULL) { + reply(550, globerr); + yyval = NULL; + } + free((char *) yyvsp[0]); + } else + yyval = yyvsp[0]; + } +break; +case 72: +#line 622 "ftp.y" + { + register int ret, dec, multby, digit; + + /* + * Convert a number that was read as decimal number + * to what it would be if it had been read as octal. + */ + dec = yyvsp[0]; + multby = 1; + ret = 0; + while (dec) { + digit = dec%10; + if (digit > 7) { + ret = -1; + break; + } + ret += digit * multby; + multby *= 8; + dec /= 10; + } + yyval = ret; + } +break; +case 73: +#line 647 "ftp.y" + { + if (logged_in) + yyval = 1; + else { + reply(530, "Please login with USER and PASS."); + yyval = 0; + } + } +break; +#line 1688 "ftp.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/usr.bin/yacc/test/ftp.tab.h b/usr.bin/yacc/test/ftp.tab.h new file mode 100644 index 0000000..24f0791 --- /dev/null +++ b/usr.bin/yacc/test/ftp.tab.h @@ -0,0 +1,63 @@ +#define A 257 +#define B 258 +#define C 259 +#define E 260 +#define F 261 +#define I 262 +#define L 263 +#define N 264 +#define P 265 +#define R 266 +#define S 267 +#define T 268 +#define SP 269 +#define CRLF 270 +#define COMMA 271 +#define STRING 272 +#define NUMBER 273 +#define USER 274 +#define PASS 275 +#define ACCT 276 +#define REIN 277 +#define QUIT 278 +#define PORT 279 +#define PASV 280 +#define TYPE 281 +#define STRU 282 +#define MODE 283 +#define RETR 284 +#define STOR 285 +#define APPE 286 +#define MLFL 287 +#define MAIL 288 +#define MSND 289 +#define MSOM 290 +#define MSAM 291 +#define MRSQ 292 +#define MRCP 293 +#define ALLO 294 +#define REST 295 +#define RNFR 296 +#define RNTO 297 +#define ABOR 298 +#define DELE 299 +#define CWD 300 +#define LIST 301 +#define NLST 302 +#define SITE 303 +#define STAT 304 +#define HELP 305 +#define NOOP 306 +#define MKD 307 +#define RMD 308 +#define PWD 309 +#define CDUP 310 +#define STOU 311 +#define SMNT 312 +#define SYST 313 +#define SIZE 314 +#define MDTM 315 +#define UMASK 316 +#define IDLE 317 +#define CHMOD 318 +#define LEXERR 319 diff --git a/usr.bin/yacc/test/ftp.y b/usr.bin/yacc/test/ftp.y new file mode 100644 index 0000000..a9ee9cd --- /dev/null +++ b/usr.bin/yacc/test/ftp.y @@ -0,0 +1,1180 @@ +/* + * Copyright (c) 1985, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)ftpcmd.y 5.20.1.1 (Berkeley) 3/2/89 + */ + +/* + * Grammar for FTP commands. + * See RFC 959. + */ + +%{ + +#ifndef lint +static char sccsid[] = "@(#)ftpcmd.y 5.20.1.1 (Berkeley) 3/2/89"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> + +#include <arpa/ftp.h> + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#include <pwd.h> +#include <setjmp.h> +#include <syslog.h> +#include <sys/stat.h> +#include <time.h> + +extern struct sockaddr_in data_dest; +extern int logged_in; +extern struct passwd *pw; +extern int guest; +extern int logging; +extern int type; +extern int form; +extern int debug; +extern int timeout; +extern int maxtimeout; +extern int pdata; +extern char hostname[], remotehost[]; +extern char proctitle[]; +extern char *globerr; +extern int usedefault; +extern int transflag; +extern char tmpline[]; +char **glob(); + +static int cmd_type; +static int cmd_form; +static int cmd_bytesz; +char cbuf[512]; +char *fromname; + +char *index(); +%} + +%token + A B C E F I + L N P R S T + + SP CRLF COMMA STRING NUMBER + + USER PASS ACCT REIN QUIT PORT + PASV TYPE STRU MODE RETR STOR + APPE MLFL MAIL MSND MSOM MSAM + MRSQ MRCP ALLO REST RNFR RNTO + ABOR DELE CWD LIST NLST SITE + STAT HELP NOOP MKD RMD PWD + CDUP STOU SMNT SYST SIZE MDTM + + UMASK IDLE CHMOD + + LEXERR + +%start cmd_list + +%% + +cmd_list: /* empty */ + | cmd_list cmd + = { + fromname = (char *) 0; + } + | cmd_list rcmd + ; + +cmd: USER SP username CRLF + = { + user((char *) $3); + free((char *) $3); + } + | PASS SP password CRLF + = { + pass((char *) $3); + free((char *) $3); + } + | PORT SP host_port CRLF + = { + usedefault = 0; + if (pdata >= 0) { + (void) close(pdata); + pdata = -1; + } + reply(200, "PORT command successful."); + } + | PASV CRLF + = { + passive(); + } + | TYPE SP type_code CRLF + = { + switch (cmd_type) { + + case TYPE_A: + if (cmd_form == FORM_N) { + reply(200, "Type set to A."); + type = cmd_type; + form = cmd_form; + } else + reply(504, "Form must be N."); + break; + + case TYPE_E: + reply(504, "Type E not implemented."); + break; + + case TYPE_I: + reply(200, "Type set to I."); + type = cmd_type; + break; + + case TYPE_L: +#if NBBY == 8 + if (cmd_bytesz == 8) { + reply(200, + "Type set to L (byte size 8)."); + type = cmd_type; + } else + reply(504, "Byte size must be 8."); +#else /* NBBY == 8 */ + UNIMPLEMENTED for NBBY != 8 +#endif /* NBBY == 8 */ + } + } + | STRU SP struct_code CRLF + = { + switch ($3) { + + case STRU_F: + reply(200, "STRU F ok."); + break; + + default: + reply(504, "Unimplemented STRU type."); + } + } + | MODE SP mode_code CRLF + = { + switch ($3) { + + case MODE_S: + reply(200, "MODE S ok."); + break; + + default: + reply(502, "Unimplemented MODE type."); + } + } + | ALLO SP NUMBER CRLF + = { + reply(202, "ALLO command ignored."); + } + | ALLO SP NUMBER SP R SP NUMBER CRLF + = { + reply(202, "ALLO command ignored."); + } + | RETR check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + retrieve((char *) 0, (char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | STOR check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + store((char *) $4, "w", 0); + if ($4 != NULL) + free((char *) $4); + } + | APPE check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + store((char *) $4, "a", 0); + if ($4 != NULL) + free((char *) $4); + } + | NLST check_login CRLF + = { + if ($2) + send_file_list("."); + } + | NLST check_login SP STRING CRLF + = { + if ($2 && $4 != NULL) + send_file_list((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | LIST check_login CRLF + = { + if ($2) + retrieve("/bin/ls -lgA", ""); + } + | LIST check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + retrieve("/bin/ls -lgA %s", (char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | STAT check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + statfilecmd((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | STAT CRLF + = { + statcmd(); + } + | DELE check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + delete((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | RNTO SP pathname CRLF + = { + if (fromname) { + renamecmd(fromname, (char *) $3); + free(fromname); + fromname = (char *) 0; + } else { + reply(503, "Bad sequence of commands."); + } + free((char *) $3); + } + | ABOR CRLF + = { + reply(225, "ABOR command successful."); + } + | CWD check_login CRLF + = { + if ($2) + cwd(pw->pw_dir); + } + | CWD check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + cwd((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | HELP CRLF + = { + help(cmdtab, (char *) 0); + } + | HELP SP STRING CRLF + = { + register char *cp = (char *)$3; + + if (strncasecmp(cp, "SITE", 4) == 0) { + cp = (char *)$3 + 4; + if (*cp == ' ') + cp++; + if (*cp) + help(sitetab, cp); + else + help(sitetab, (char *) 0); + } else + help(cmdtab, (char *) $3); + } + | NOOP CRLF + = { + reply(200, "NOOP command successful."); + } + | MKD check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + makedir((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | RMD check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + removedir((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | PWD check_login CRLF + = { + if ($2) + pwd(); + } + | CDUP check_login CRLF + = { + if ($2) + cwd(".."); + } + | SITE SP HELP CRLF + = { + help(sitetab, (char *) 0); + } + | SITE SP HELP SP STRING CRLF + = { + help(sitetab, (char *) $5); + } + | SITE SP UMASK check_login CRLF + = { + int oldmask; + + if ($4) { + oldmask = umask(0); + (void) umask(oldmask); + reply(200, "Current UMASK is %03o", oldmask); + } + } + | SITE SP UMASK check_login SP octal_number CRLF + = { + int oldmask; + + if ($4) { + if (($6 == -1) || ($6 > 0777)) { + reply(501, "Bad UMASK value"); + } else { + oldmask = umask($6); + reply(200, + "UMASK set to %03o (was %03o)", + $6, oldmask); + } + } + } + | SITE SP CHMOD check_login SP octal_number SP pathname CRLF + = { + if ($4 && ($8 != NULL)) { + if ($6 > 0777) + reply(501, + "CHMOD: Mode value must be between 0 and 0777"); + else if (chmod((char *) $8, $6) < 0) + perror_reply(550, (char *) $8); + else + reply(200, "CHMOD command successful."); + } + if ($8 != NULL) + free((char *) $8); + } + | SITE SP IDLE CRLF + = { + reply(200, + "Current IDLE time limit is %d seconds; max %d", + timeout, maxtimeout); + } + | SITE SP IDLE SP NUMBER CRLF + = { + if ($5 < 30 || $5 > maxtimeout) { + reply(501, + "Maximum IDLE time must be between 30 and %d seconds", + maxtimeout); + } else { + timeout = $5; + (void) alarm((unsigned) timeout); + reply(200, + "Maximum IDLE time set to %d seconds", + timeout); + } + } + | STOU check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + store((char *) $4, "w", 1); + if ($4 != NULL) + free((char *) $4); + } + | SYST CRLF + = { +#ifdef unix +#ifdef BSD + reply(215, "UNIX Type: L%d Version: BSD-%d", + NBBY, BSD); +#else /* BSD */ + reply(215, "UNIX Type: L%d", NBBY); +#endif /* BSD */ +#else /* unix */ + reply(215, "UNKNOWN Type: L%d", NBBY); +#endif /* unix */ + } + + /* + * SIZE is not in RFC959, but Postel has blessed it and + * it will be in the updated RFC. + * + * Return size of file in a format suitable for + * using with RESTART (we just count bytes). + */ + | SIZE check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + sizecmd((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + + /* + * MDTM is not in RFC959, but Postel has blessed it and + * it will be in the updated RFC. + * + * Return modification time of file as an ISO 3307 + * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx + * where xxx is the fractional second (of any precision, + * not necessarily 3 digits) + */ + | MDTM check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) { + struct stat stbuf; + if (stat((char *) $4, &stbuf) < 0) + perror_reply(550, "%s", (char *) $4); + else if ((stbuf.st_mode&S_IFMT) != S_IFREG) { + reply(550, "%s: not a plain file.", + (char *) $4); + } else { + register struct tm *t; + struct tm *gmtime(); + t = gmtime(&stbuf.st_mtime); + reply(213, + "19%02d%02d%02d%02d%02d%02d", + t->tm_year, t->tm_mon+1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + } + } + if ($4 != NULL) + free((char *) $4); + } + | QUIT CRLF + = { + reply(221, "Goodbye."); + dologout(0); + } + | error CRLF + = { + yyerrok; + } + ; +rcmd: RNFR check_login SP pathname CRLF + = { + char *renamefrom(); + + if ($2 && $4) { + fromname = renamefrom((char *) $4); + if (fromname == (char *) 0 && $4) { + free((char *) $4); + } + } + } + ; + +username: STRING + ; + +password: /* empty */ + = { + *(char **)&($$) = ""; + } + | STRING + ; + +byte_size: NUMBER + ; + +host_port: NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA + NUMBER COMMA NUMBER + = { + register char *a, *p; + + a = (char *)&data_dest.sin_addr; + a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7; + p = (char *)&data_dest.sin_port; + p[0] = $9; p[1] = $11; + data_dest.sin_family = AF_INET; + } + ; + +form_code: N + = { + $$ = FORM_N; + } + | T + = { + $$ = FORM_T; + } + | C + = { + $$ = FORM_C; + } + ; + +type_code: A + = { + cmd_type = TYPE_A; + cmd_form = FORM_N; + } + | A SP form_code + = { + cmd_type = TYPE_A; + cmd_form = $3; + } + | E + = { + cmd_type = TYPE_E; + cmd_form = FORM_N; + } + | E SP form_code + = { + cmd_type = TYPE_E; + cmd_form = $3; + } + | I + = { + cmd_type = TYPE_I; + } + | L + = { + cmd_type = TYPE_L; + cmd_bytesz = NBBY; + } + | L SP byte_size + = { + cmd_type = TYPE_L; + cmd_bytesz = $3; + } + /* this is for a bug in the BBN ftp */ + | L byte_size + = { + cmd_type = TYPE_L; + cmd_bytesz = $2; + } + ; + +struct_code: F + = { + $$ = STRU_F; + } + | R + = { + $$ = STRU_R; + } + | P + = { + $$ = STRU_P; + } + ; + +mode_code: S + = { + $$ = MODE_S; + } + | B + = { + $$ = MODE_B; + } + | C + = { + $$ = MODE_C; + } + ; + +pathname: pathstring + = { + /* + * Problem: this production is used for all pathname + * processing, but only gives a 550 error reply. + * This is a valid reply in some cases but not in others. + */ + if (logged_in && $1 && strncmp((char *) $1, "~", 1) == 0) { + *(char **)&($$) = *glob((char *) $1); + if (globerr != NULL) { + reply(550, globerr); + $$ = NULL; + } + free((char *) $1); + } else + $$ = $1; + } + ; + +pathstring: STRING + ; + +octal_number: NUMBER + = { + register int ret, dec, multby, digit; + + /* + * Convert a number that was read as decimal number + * to what it would be if it had been read as octal. + */ + dec = $1; + multby = 1; + ret = 0; + while (dec) { + digit = dec%10; + if (digit > 7) { + ret = -1; + break; + } + ret += digit * multby; + multby *= 8; + dec /= 10; + } + $$ = ret; + } + ; + +check_login: /* empty */ + = { + if (logged_in) + $$ = 1; + else { + reply(530, "Please login with USER and PASS."); + $$ = 0; + } + } + ; + +%% + +extern jmp_buf errcatch; + +#define CMD 0 /* beginning of command */ +#define ARGS 1 /* expect miscellaneous arguments */ +#define STR1 2 /* expect SP followed by STRING */ +#define STR2 3 /* expect STRING */ +#define OSTR 4 /* optional SP then STRING */ +#define ZSTR1 5 /* SP then optional STRING */ +#define ZSTR2 6 /* optional STRING after SP */ +#define SITECMD 7 /* SITE command */ +#define NSTR 8 /* Number followed by a string */ + +struct tab { + char *name; + short token; + short state; + short implemented; /* 1 if command is implemented */ + char *help; +}; + +struct tab cmdtab[] = { /* In order defined in RFC 765 */ + { "USER", USER, STR1, 1, "<sp> username" }, + { "PASS", PASS, ZSTR1, 1, "<sp> password" }, + { "ACCT", ACCT, STR1, 0, "(specify account)" }, + { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, + { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, + { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, + { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" }, + { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, + { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" }, + { "STRU", STRU, ARGS, 1, "(specify file structure)" }, + { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, + { "RETR", RETR, STR1, 1, "<sp> file-name" }, + { "STOR", STOR, STR1, 1, "<sp> file-name" }, + { "APPE", APPE, STR1, 1, "<sp> file-name" }, + { "MLFL", MLFL, OSTR, 0, "(mail file)" }, + { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, + { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, + { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, + { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, + { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, + { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, + { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, + { "REST", REST, ARGS, 0, "(restart command)" }, + { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, + { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, + { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, + { "DELE", DELE, STR1, 1, "<sp> file-name" }, + { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, + { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, + { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, + { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, + { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, + { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, + { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, + { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, + { "NOOP", NOOP, ARGS, 1, "" }, + { "MKD", MKD, STR1, 1, "<sp> path-name" }, + { "XMKD", MKD, STR1, 1, "<sp> path-name" }, + { "RMD", RMD, STR1, 1, "<sp> path-name" }, + { "XRMD", RMD, STR1, 1, "<sp> path-name" }, + { "PWD", PWD, ARGS, 1, "(return current directory)" }, + { "XPWD", PWD, ARGS, 1, "(return current directory)" }, + { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, + { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, + { "STOU", STOU, STR1, 1, "<sp> file-name" }, + { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, + { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, + { NULL, 0, 0, 0, 0 } +}; + +struct tab sitetab[] = { + { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, + { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, + { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, + { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, + { NULL, 0, 0, 0, 0 } +}; + +struct tab * +lookup(p, cmd) + register struct tab *p; + char *cmd; +{ + + for (; p->name != NULL; p++) + if (strcmp(cmd, p->name) == 0) + return (p); + return (0); +} + +#include <arpa/telnet.h> + +/* + * getline - a hacked up version of fgets to ignore TELNET escape codes. + */ +char * +getline(s, n, iop) + char *s; + register FILE *iop; +{ + register c; + register char *cs; + + cs = s; +/* tmpline may contain saved command from urgent mode interruption */ + for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { + *cs++ = tmpline[c]; + if (tmpline[c] == '\n') { + *cs++ = '\0'; + if (debug) + syslog(LOG_DEBUG, "command: %s", s); + tmpline[0] = '\0'; + return(s); + } + if (c == 0) + tmpline[0] = '\0'; + } + while ((c = getc(iop)) != EOF) { + c &= 0377; + if (c == IAC) { + if ((c = getc(iop)) != EOF) { + c &= 0377; + switch (c) { + case WILL: + case WONT: + c = getc(iop); + printf("%c%c%c", IAC, DONT, 0377&c); + (void) fflush(stdout); + continue; + case DO: + case DONT: + c = getc(iop); + printf("%c%c%c", IAC, WONT, 0377&c); + (void) fflush(stdout); + continue; + case IAC: + break; + default: + continue; /* ignore command */ + } + } + } + *cs++ = c; + if (--n <= 0 || c == '\n') + break; + } + if (c == EOF && cs == s) + return (NULL); + *cs++ = '\0'; + if (debug) + syslog(LOG_DEBUG, "command: %s", s); + return (s); +} + +static int +toolong() +{ + time_t now; + extern char *ctime(); + extern time_t time(); + + reply(421, + "Timeout (%d seconds): closing control connection.", timeout); + (void) time(&now); + if (logging) { + syslog(LOG_INFO, + "User %s timed out after %d seconds at %s", + (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now)); + } + dologout(1); +} + +yylex() +{ + static int cpos, state; + register char *cp, *cp2; + register struct tab *p; + int n; + char c, *strpbrk(); + char *copy(); + + for (;;) { + switch (state) { + + case CMD: + (void) signal(SIGALRM, toolong); + (void) alarm((unsigned) timeout); + if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { + reply(221, "You could at least say goodbye."); + dologout(0); + } + (void) alarm(0); +#ifdef SETPROCTITLE + if (strncasecmp(cbuf, "PASS", 4) != NULL) + setproctitle("%s: %s", proctitle, cbuf); +#endif /* SETPROCTITLE */ + if ((cp = index(cbuf, '\r'))) { + *cp++ = '\n'; + *cp = '\0'; + } + if ((cp = strpbrk(cbuf, " \n"))) + cpos = cp - cbuf; + if (cpos == 0) + cpos = 4; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + upper(cbuf); + p = lookup(cmdtab, cbuf); + cbuf[cpos] = c; + if (p != 0) { + if (p->implemented == 0) { + nack(p->name); + longjmp(errcatch,0); + /* NOTREACHED */ + } + state = p->state; + *(char **)&yylval = p->name; + return (p->token); + } + break; + + case SITECMD: + if (cbuf[cpos] == ' ') { + cpos++; + return (SP); + } + cp = &cbuf[cpos]; + if ((cp2 = strpbrk(cp, " \n"))) + cpos = cp2 - cbuf; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + upper(cp); + p = lookup(sitetab, cp); + cbuf[cpos] = c; + if (p != 0) { + if (p->implemented == 0) { + state = CMD; + nack(p->name); + longjmp(errcatch,0); + /* NOTREACHED */ + } + state = p->state; + *(char **)&yylval = p->name; + return (p->token); + } + state = CMD; + break; + + case OSTR: + if (cbuf[cpos] == '\n') { + state = CMD; + return (CRLF); + } + /* FALLTHROUGH */ + + case STR1: + case ZSTR1: + dostr1: + if (cbuf[cpos] == ' ') { + cpos++; + state = state == OSTR ? STR2 : ++state; + return (SP); + } + break; + + case ZSTR2: + if (cbuf[cpos] == '\n') { + state = CMD; + return (CRLF); + } + /* FALLTHROUGH */ + + case STR2: + cp = &cbuf[cpos]; + n = strlen(cp); + cpos += n - 1; + /* + * Make sure the string is nonempty and \n terminated. + */ + if (n > 1 && cbuf[cpos] == '\n') { + cbuf[cpos] = '\0'; + *(char **)&yylval = copy(cp); + cbuf[cpos] = '\n'; + state = ARGS; + return (STRING); + } + break; + + case NSTR: + if (cbuf[cpos] == ' ') { + cpos++; + return (SP); + } + if (isdigit(cbuf[cpos])) { + cp = &cbuf[cpos]; + while (isdigit(cbuf[++cpos])) + ; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + yylval = atoi(cp); + cbuf[cpos] = c; + state = STR1; + return (NUMBER); + } + state = STR1; + goto dostr1; + + case ARGS: + if (isdigit(cbuf[cpos])) { + cp = &cbuf[cpos]; + while (isdigit(cbuf[++cpos])) + ; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + yylval = atoi(cp); + cbuf[cpos] = c; + return (NUMBER); + } + switch (cbuf[cpos++]) { + + case '\n': + state = CMD; + return (CRLF); + + case ' ': + return (SP); + + case ',': + return (COMMA); + + case 'A': + case 'a': + return (A); + + case 'B': + case 'b': + return (B); + + case 'C': + case 'c': + return (C); + + case 'E': + case 'e': + return (E); + + case 'F': + case 'f': + return (F); + + case 'I': + case 'i': + return (I); + + case 'L': + case 'l': + return (L); + + case 'N': + case 'n': + return (N); + + case 'P': + case 'p': + return (P); + + case 'R': + case 'r': + return (R); + + case 'S': + case 's': + return (S); + + case 'T': + case 't': + return (T); + + } + break; + + default: + fatal("Unknown state in scanner."); + } + yyerror((char *) 0); + state = CMD; + longjmp(errcatch,0); + } +} + +upper(s) + register char *s; +{ + while (*s != '\0') { + if (islower(*s)) + *s = toupper(*s); + s++; + } +} + +char * +copy(s) + char *s; +{ + char *p; + extern char *malloc(), *strcpy(); + + p = malloc((unsigned) strlen(s) + 1); + if (p == NULL) + fatal("Ran out of memory."); + (void) strcpy(p, s); + return (p); +} + +help(ctab, s) + struct tab *ctab; + char *s; +{ + register struct tab *c; + register int width, NCMDS; + char *type; + + if (ctab == sitetab) + type = "SITE "; + else + type = ""; + width = 0, NCMDS = 0; + for (c = ctab; c->name != NULL; c++) { + int len = strlen(c->name); + + if (len > width) + width = len; + NCMDS++; + } + width = (width + 8) &~ 7; + if (s == 0) { + register int i, j, w; + int columns, lines; + + lreply(214, "The following %scommands are recognized %s.", + type, "(* =>'s unimplemented)"); + columns = 76 / width; + if (columns == 0) + columns = 1; + lines = (NCMDS + columns - 1) / columns; + for (i = 0; i < lines; i++) { + printf(" "); + for (j = 0; j < columns; j++) { + c = ctab + j * lines + i; + printf("%s%c", c->name, + c->implemented ? ' ' : '*'); + if (c + lines >= &ctab[NCMDS]) + break; + w = strlen(c->name) + 1; + while (w < width) { + putchar(' '); + w++; + } + } + printf("\r\n"); + } + (void) fflush(stdout); + reply(214, "Direct comments to ftp-bugs@%s.", hostname); + return; + } + upper(s); + c = lookup(ctab, s); + if (c == (struct tab *)0) { + reply(502, "Unknown command %s.", s); + return; + } + if (c->implemented) + reply(214, "Syntax: %s%s %s", type, c->name, c->help); + else + reply(214, "%s%-*s\t%s; unimplemented.", type, width, + c->name, c->help); +} + +sizecmd(filename) +char *filename; +{ + switch (type) { + case TYPE_L: + case TYPE_I: { + struct stat stbuf; + if (stat(filename, &stbuf) < 0 || + (stbuf.st_mode&S_IFMT) != S_IFREG) + reply(550, "%s: not a plain file.", filename); + else + reply(213, "%lu", stbuf.st_size); + break;} + case TYPE_A: { + FILE *fin; + register int c, count; + struct stat stbuf; + fin = fopen(filename, "r"); + if (fin == NULL) { + perror_reply(550, filename); + return; + } + if (fstat(fileno(fin), &stbuf) < 0 || + (stbuf.st_mode&S_IFMT) != S_IFREG) { + reply(550, "%s: not a plain file.", filename); + (void) fclose(fin); + return; + } + + count = 0; + while((c=getc(fin)) != EOF) { + if (c == '\n') /* will get expanded to \r\n */ + count++; + count++; + } + (void) fclose(fin); + + reply(213, "%ld", count); + break;} + default: + reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); + } +} diff --git a/usr.bin/yacc/verbose.c b/usr.bin/yacc/verbose.c new file mode 100644 index 0000000..33ae265 --- /dev/null +++ b/usr.bin/yacc/verbose.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)verbose.c 5.3 (Berkeley) 1/20/91"; +#endif /* not lint */ + +#include "defs.h" + +static short *null_rules; + +verbose() +{ + register int i; + + if (!vflag) return; + + null_rules = (short *) MALLOC(nrules*sizeof(short)); + if (null_rules == 0) no_space(); + fprintf(verbose_file, "\f\n"); + for (i = 0; i < nstates; i++) + print_state(i); + FREE(null_rules); + + if (nunused) + log_unused(); + if (SRtotal || RRtotal) + log_conflicts(); + + fprintf(verbose_file, "\n\n%d terminals, %d nonterminals\n", ntokens, + nvars); + fprintf(verbose_file, "%d grammar rules, %d states\n", nrules - 2, nstates); +} + + +log_unused() +{ + register int i; + register short *p; + + fprintf(verbose_file, "\n\nRules never reduced:\n"); + for (i = 3; i < nrules; ++i) + { + if (!rules_used[i]) + { + fprintf(verbose_file, "\t%s :", symbol_name[rlhs[i]]); + for (p = ritem + rrhs[i]; *p >= 0; ++p) + fprintf(verbose_file, " %s", symbol_name[*p]); + fprintf(verbose_file, " (%d)\n", i - 2); + } + } +} + + +log_conflicts() +{ + register int i; + + fprintf(verbose_file, "\n\n"); + for (i = 0; i < nstates; i++) + { + if (SRconflicts[i] || RRconflicts[i]) + { + fprintf(verbose_file, "State %d contains ", i); + if (SRconflicts[i] == 1) + fprintf(verbose_file, "1 shift/reduce conflict"); + else if (SRconflicts[i] > 1) + fprintf(verbose_file, "%d shift/reduce conflicts", + SRconflicts[i]); + if (SRconflicts[i] && RRconflicts[i]) + fprintf(verbose_file, ", "); + if (RRconflicts[i] == 1) + fprintf(verbose_file, "1 reduce/reduce conflict"); + else if (RRconflicts[i] > 1) + fprintf(verbose_file, "%d reduce/reduce conflicts", + RRconflicts[i]); + fprintf(verbose_file, ".\n"); + } + } +} + + +print_state(state) +int state; +{ + if (state) + fprintf(verbose_file, "\n\n"); + if (SRconflicts[state] || RRconflicts[state]) + print_conflicts(state); + fprintf(verbose_file, "state %d\n", state); + print_core(state); + print_nulls(state); + print_actions(state); +} + + +print_conflicts(state) +int state; +{ + register int symbol, act, number; + register action *p; + + symbol = -1; + for (p = parser[state]; p; p = p->next) + { + if (p->suppressed == 2) + continue; + + if (p->symbol != symbol) + { + symbol = p->symbol; + number = p->number; + if (p->action_code == SHIFT) + act = SHIFT; + else + act = REDUCE; + } + else if (p->suppressed == 1) + { + if (state == final_state && symbol == 0) + { + fprintf(verbose_file, "%d: shift/reduce conflict \ +(accept, reduce %d) on $end\n", state, p->number - 2); + } + else + { + if (act == SHIFT) + { + fprintf(verbose_file, "%d: shift/reduce conflict \ +(shift %d, reduce %d) on %s\n", state, number, p->number - 2, + symbol_name[symbol]); + } + else + { + fprintf(verbose_file, "%d: reduce/reduce conflict \ +(reduce %d, reduce %d) on %s\n", state, number - 2, p->number - 2, + symbol_name[symbol]); + } + } + } + } +} + + +print_core(state) +int state; +{ + register int i; + register int k; + register int rule; + register core *statep; + register short *sp; + register short *sp1; + + statep = state_table[state]; + k = statep->nitems; + + for (i = 0; i < k; i++) + { + sp1 = sp = ritem + statep->items[i]; + + while (*sp >= 0) ++sp; + rule = -(*sp); + fprintf(verbose_file, "\t%s : ", symbol_name[rlhs[rule]]); + + for (sp = ritem + rrhs[rule]; sp < sp1; sp++) + fprintf(verbose_file, "%s ", symbol_name[*sp]); + + putc('.', verbose_file); + + while (*sp >= 0) + { + fprintf(verbose_file, " %s", symbol_name[*sp]); + sp++; + } + fprintf(verbose_file, " (%d)\n", -2 - *sp); + } +} + + +print_nulls(state) +int state; +{ + register action *p; + register int i, j, k, nnulls; + + nnulls = 0; + for (p = parser[state]; p; p = p->next) + { + if (p->action_code == REDUCE && + (p->suppressed == 0 || p->suppressed == 1)) + { + i = p->number; + if (rrhs[i] + 1 == rrhs[i+1]) + { + for (j = 0; j < nnulls && i > null_rules[j]; ++j) + continue; + + if (j == nnulls) + { + ++nnulls; + null_rules[j] = i; + } + else if (i != null_rules[j]) + { + ++nnulls; + for (k = nnulls - 1; k > j; --k) + null_rules[k] = null_rules[k-1]; + null_rules[j] = i; + } + } + } + } + + for (i = 0; i < nnulls; ++i) + { + j = null_rules[i]; + fprintf(verbose_file, "\t%s : . (%d)\n", symbol_name[rlhs[j]], + j - 2); + } + fprintf(verbose_file, "\n"); +} + + +print_actions(stateno) +int stateno; +{ + register action *p; + register shifts *sp; + register int as; + + if (stateno == final_state) + fprintf(verbose_file, "\t$end accept\n"); + + p = parser[stateno]; + if (p) + { + print_shifts(p); + print_reductions(p, defred[stateno]); + } + + sp = shift_table[stateno]; + if (sp && sp->nshifts > 0) + { + as = accessing_symbol[sp->shift[sp->nshifts - 1]]; + if (ISVAR(as)) + print_gotos(stateno); + } +} + + +print_shifts(p) +register action *p; +{ + register int count; + register action *q; + + count = 0; + for (q = p; q; q = q->next) + { + if (q->suppressed < 2 && q->action_code == SHIFT) + ++count; + } + + if (count > 0) + { + for (; p; p = p->next) + { + if (p->action_code == SHIFT && p->suppressed == 0) + fprintf(verbose_file, "\t%s shift %d\n", + symbol_name[p->symbol], p->number); + } + } +} + + +print_reductions(p, defred) +register action *p; +register int defred; +{ + register int k, anyreds; + register action *q; + + anyreds = 0; + for (q = p; q ; q = q->next) + { + if (q->action_code == REDUCE && q->suppressed < 2) + { + anyreds = 1; + break; + } + } + + if (anyreds == 0) + fprintf(verbose_file, "\t. error\n"); + else + { + for (; p; p = p->next) + { + if (p->action_code == REDUCE && p->number != defred) + { + k = p->number - 2; + if (p->suppressed == 0) + fprintf(verbose_file, "\t%s reduce %d\n", + symbol_name[p->symbol], k); + } + } + + if (defred > 0) + fprintf(verbose_file, "\t. reduce %d\n", defred - 2); + } +} + + +print_gotos(stateno) +int stateno; +{ + register int i, k; + register int as; + register short *to_state; + register shifts *sp; + + putc('\n', verbose_file); + sp = shift_table[stateno]; + to_state = sp->shift; + for (i = 0; i < sp->nshifts; ++i) + { + k = to_state[i]; + as = accessing_symbol[k]; + if (ISVAR(as)) + fprintf(verbose_file, "\t%s goto %d\n", symbol_name[as], k); + } +} diff --git a/usr.bin/yacc/warshall.c b/usr.bin/yacc/warshall.c new file mode 100644 index 0000000..4672244 --- /dev/null +++ b/usr.bin/yacc/warshall.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)warshall.c 5.4 (Berkeley) 5/24/93"; +#endif /* not lint */ + +#include "defs.h" + +transitive_closure(R, n) +unsigned *R; +int n; +{ + register int rowsize; + register unsigned i; + register unsigned *rowj; + register unsigned *rp; + register unsigned *rend; + register unsigned *ccol; + register unsigned *relend; + register unsigned *cword; + register unsigned *rowi; + + rowsize = WORDSIZE(n); + relend = R + n*rowsize; + + cword = R; + i = 0; + rowi = R; + while (rowi < relend) + { + ccol = cword; + rowj = R; + + while (rowj < relend) + { + if (*ccol & (1 << i)) + { + rp = rowi; + rend = rowj + rowsize; + while (rowj < rend) + *rowj++ |= *rp++; + } + else + { + rowj += rowsize; + } + + ccol += rowsize; + } + + if (++i >= BITS_PER_WORD) + { + i = 0; + cword++; + } + + rowi += rowsize; + } +} + +reflexive_transitive_closure(R, n) +unsigned *R; +int n; +{ + register int rowsize; + register unsigned i; + register unsigned *rp; + register unsigned *relend; + + transitive_closure(R, n); + + rowsize = WORDSIZE(n); + relend = R + n*rowsize; + + i = 0; + rp = R; + while (rp < relend) + { + *rp |= (1 << i); + if (++i >= BITS_PER_WORD) + { + i = 0; + rp++; + } + + rp += rowsize; + } +} diff --git a/usr.bin/yacc/yacc.1 b/usr.bin/yacc/yacc.1 new file mode 100644 index 0000000..787dc00 --- /dev/null +++ b/usr.bin/yacc/yacc.1 @@ -0,0 +1,145 @@ +.\" Copyright (c) 1989, 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Robert Paul Corbett. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)yacc.1 5.8 (Berkeley) 5/24/93 +.\" +.TH YACC 1 "May 24, 1993" +.UC 6 +.SH NAME +yacc \- an LALR(1) parser generator +.SH SYNOPSIS +.B yacc [ -dlrtv ] [ -b +.I file_prefix +.B ] [ -p +.I symbol_prefix +.B ] +.I filename +.SH DESCRIPTION +.I Yacc +reads the grammar specification in the file +.I filename +and generates an LR(1) parser for it. +The parsers consist of a set of LALR(1) parsing tables and a driver routine +written in the C programming language. +.I Yacc +normally writes the parse tables and the driver routine to the file +.IR y.tab.c. +.PP +The following options are available: +.RS +.TP +\fB-b \fIfile_prefix\fR +The +.B -b +option changes the prefix prepended to the output file names to +the string denoted by +.IR file_prefix. +The default prefix is the character +.IR y. +.TP +.B -d +The \fB-d\fR option causes the header file +.IR y.tab.h +to be written. +.TP +.B -l +If the +.B -l +option is not specified, +.I yacc +will insert #line directives in the generated code. +The #line directives let the C compiler relate errors in the +generated code to the user's original code. +If the \fB-l\fR option is specified, +.I yacc +will not insert the #line directives. +Any #line directives specified by the user will be retained. +.TP +\fB-p \fIsymbol_prefix\fR +The +.B -p +option changes the prefix prepended to yacc-generated symbols to +the string denoted by +.IR symbol_prefix. +The default prefix is the string +.IR yy. +.TP +.B -r +The +.B -r +option causes +.I yacc +to produce separate files for code and tables. The code file +is named +.IR y.code.c, +and the tables file is named +.IR y.tab.c. +.TP +.B -t +The +.B -t +option changes the preprocessor directives generated by +.I yacc +so that debugging statements will be incorporated in the compiled code. +.TP +.B -v +The +.B -v +option causes a human-readable description of the generated parser to +be written to the file +.IR y.output. +.RE +.PP +If the environment variable TMPDIR is set, the string denoted by +TMPDIR will be used as the name of the directory where the temporary +files are created. +.SH FILES +.IR y.code.c +.br +.IR y.tab.c +.br +.IR y.tab.h +.br +.IR y.output +.br +.IR /tmp/yacc.aXXXXXX +.br +.IR /tmp/yacc.tXXXXXX +.br +.IR /tmp/yacc.uXXXXXX +.SH DIAGNOSTICS +If there are rules that are never reduced, the number of such rules is +reported on standard error. +If there are any LALR(1) conflicts, the number of conflicts is reported +on standard error. diff --git a/usr.bin/yacc/yyfix.1 b/usr.bin/yacc/yyfix.1 new file mode 100644 index 0000000..7af0a9e --- /dev/null +++ b/usr.bin/yacc/yyfix.1 @@ -0,0 +1,112 @@ +.\" Copyright (c) 1990, 1991 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)yyfix.1 5.4 (Berkeley) 3/23/93 +.\" +.Dd March 23, 1993 +.Dt YYFIX 1 +.Os BSD 4.4 +.Sh NAME +.Nm yyfix +.Nd extract tables from y.tab.c +.Sh SYNOPSIS +.Nm yyfix +.Ar file +.Op Ar tables +.Sh DESCRIPTION +Programs have historically used a script (often named ``:yyfix'') to +extract tables from the +.Xr yacc 1 +generated file +.Pa y.tab.c . +As the names of the tables generated by the current version of +.Xr yacc +are different from those of historical versions of +.Xr yacc , +the shell script +.Nm yyfix +is provided to simplify the transition. +.Pp +The first (and required) argument to +.Nm yyfix +is the name of the file where the extracted tables should be stored. +.Pp +If further command line arguments are specified, they are taken as +the list of tables to be extracted. +Otherwise, +.Nm yyfix +attempts to determine if the +.Pa y.tab.c +file is from an old or new +.Xr yacc , +and extracts the appropriate tables. +.Pp +The tables +.Dq yyexca , +.Dq yyact , +.Dq yypact , +.Dq yypgo , +.Dq yyr1 , +.Dq yyr2 , +.Dq yychk , +and +.Dq yydef +are extracted +from historical versions of +.Xr yacc . +.Pp +The tables +.Dq yylhs , +.Dq yylen , +.Dq yydefred , +.Dq yydgoto , +.Dq yysindex , +.Dq yyrindex , +.Dq yygindex , +.Dq yytable , +.Dq yyname , +.Dq yyrule , +and +.Dq yycheck , +are extracted from the current version of +.Xr yacc . +.Sh FILES +.Bl -tag -width y.tab.c +.It Pa y.tab.c +File from which tables are extracted. +.El +.Sh SEE ALSO +.Xr yacc 1 +.Sh HISTORY +The +.Nm +command appears in +.Bx 4.4 . diff --git a/usr.bin/yacc/yyfix.sh b/usr.bin/yacc/yyfix.sh new file mode 100644 index 0000000..29085f9 --- /dev/null +++ b/usr.bin/yacc/yyfix.sh @@ -0,0 +1,71 @@ +#!/bin/sh - +# +# Copyright (c) 1990 The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)yyfix.sh 5.2 (Berkeley) 5/12/90 +# +OLDYACC="yyexca yyact yypact yypgo yyr1 yyr2 yychk yydef" +NEWYACC="yylhs yylen yydefred yydgoto yysindex yyrindex yygindex \ + yytable yycheck" + +file=$1 +>$file +shift + +if [ $# -eq 0 ] ; then + if grep yylhs y.tab.c > /dev/null ; then + if grep yyname y.tab.c > /dev/null ; then + NEWYACC="$NEWYACC yyname" + fi + if grep yyrule y.tab.c > /dev/null ; then + NEWYACC="$NEWYACC yyrule" + fi + set $NEWYACC + else + set $OLDYACC + fi +fi + +for i +do +ed - y.tab.c << END +/^\(.*\)$i[ ]*\[]/s//extern \1 $i[];\\ +\1 $i []/ +.ka +/}/kb +'br $file +'a,.w $file +'a,.d +w +q +END +done |