fatbase

portable OpenBSD tools
git clone git://git.2f30.org/fatbase.git
Log | Files | Refs

commit ed21e29ea4465ee431ddf57c02869955b47d74a2
parent 121f6601f24e6f9e5218ebefeec388514a918664
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Fri Nov 21 20:10:39 +0100

add yacc

Diffstat:
yacc/Makefile | 19+++++++++++++++++++
yacc/closure.c | 250+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/defs.h | 366+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/error.c | 323+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/lalr.c | 601+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/lr0.c | 504+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/main.c | 362+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/mkpar.c | 370+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/output.c | 1205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/reader.c | 1858+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/reallocarray.c | 38++++++++++++++++++++++++++++++++++++++
yacc/skeleton.c | 404+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/symtab.c | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/util.h | 3+++
yacc/verbose.c | 351+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/warshall.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/yacc.1 | 256+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/yyfix.1 | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yacc/yyfix.sh | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19 files changed, 7342 insertions(+), 0 deletions(-)
diff --git a/yacc/Makefile b/yacc/Makefile @@ -0,0 +1,19 @@ +build: clean + cc -c *.c + cc -o yacc *.o + +clean: + rm -f *.o yacc + +# $OpenBSD: Makefile,v 1.5 2010/10/17 22:54:37 schwarze Exp $ +# +#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 +#MAN= yacc.1 yyfix.1 +# +#beforeinstall: +# ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ +# ${.CURDIR}/yyfix.sh ${DESTDIR}${BINDIR}/yyfix +# +#.include <bsd.prog.mk> diff --git a/yacc/closure.c b/yacc/closure.c @@ -0,0 +1,250 @@ +/* $OpenBSD: closure.c,v 1.13 2014/03/13 01:18:22 tedu Exp $ */ +/* $NetBSD: closure.c,v 1.4 1996/03/19 03:21:29 jtc Exp $ */ + +/* + * 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. 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. + */ + +#include "defs.h" + +short *itemset; +short *itemsetend; +unsigned *ruleset; + +static unsigned *first_derives; +static unsigned *EFF; + + +void +set_EFF(void) +{ + unsigned int *row; + int symbol, rowsize, i, rule; + short *sp; + + 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 +} + + +void +set_first_derives(void) +{ + unsigned int *rrow, *vrow; + unsigned int k, cword = 0; + int i, j, rule, rulesetsize, varsetsize; + short *rp; + + 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); +} + + +void +closure(short *nucleus, int n) +{ + unsigned int i, word; + short *csp, *csend; + unsigned int *dsp, *rsp, *rsend; + int rulesetsize; + int ruleno, symbol, itemno; + + rulesetsize = WORDSIZE(nrules); + rsend = ruleset + rulesetsize; + memset(ruleset, 0, rulesetsize * sizeof(*ruleset)); + + 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 +} + + + +void +finalize_closure(void) +{ + free(itemset); + free(ruleset); + free(first_derives + ntokens * WORDSIZE(nrules)); +} + + +#ifdef DEBUG + +void +print_closure(int n) +{ + short *isp; + + printf("\n\nn = %d\n\n", n); + for (isp = itemset; isp < itemsetend; isp++) + printf(" %d\n", *isp); +} + +void +print_EFF(void) +{ + int i, j; + unsigned int *rowp; + unsigned int k, word; + + 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]); + } + } +} + +void +print_first_derives(void) +{ + int i, j; + unsigned int *rp; + unsigned int k, cword = 0; + + 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/yacc/defs.h b/yacc/defs.h @@ -0,0 +1,366 @@ +/* $OpenBSD: defs.h,v 1.17 2014/03/08 01:05:39 tedu Exp $ */ +/* $NetBSD: defs.h,v 1.6 1996/03/19 03:21:30 jtc Exp $ */ + +/* + * 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. 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> +#include <string.h> +#include <stdlib.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 +#define EXPECT 10 + + +/* 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 NUMERIC_VALUE(c) ((c) - '0') + + +/* symbol macros */ + +#define ISTOKEN(s) ((s) < start_symbol) +#define ISVAR(s) ((s) >= start_symbol) + + +/* storage allocation macros */ + +#define NEW(t) ((t*)allocate(sizeof(t))) +#define NEW2(n,t) ((t*)allocate((n)*sizeof(t))) + + +/* 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 *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 SRexpect; +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 void *allocate(size_t); +extern bucket *lookup(char *); +extern bucket *make_bucket(char *); +extern void set_first_derives(void); +extern void closure(short *, int); +extern void finalize_closure(void); + +extern void fatal(char *); + +extern void reflexive_transitive_closure(unsigned *, int); +extern void done(int); + +extern void no_space(void); +extern void open_error(char *); +extern void open_write_error(char *); +extern void unexpected_EOF(void); +extern void print_pos(char *, char *); +extern void syntax_error(int, char *, char *); +extern void unterminated_comment(int, char *, char *); +extern void unterminated_string(int, char *, char *); +extern void unterminated_text(int, char *, char *); +extern void unterminated_union(int, char *, char *); +extern void over_unionized(char *); +extern void illegal_tag(int, char *, char *); +extern void illegal_character(char *); +extern void used_reserved(char *); +extern void tokenized_start(char *); +extern void retyped_warning(char *); +extern void reprec_warning(char *); +extern void revalued_warning(char *); +extern void terminal_start(char *); +extern void restarted_warning(void); +extern void no_grammar(void); +extern void terminal_lhs(int); +extern void prec_redeclared(void); +extern void unterminated_action(int, char *, char *); +extern void dollar_warning(int, int); +extern void dollar_error(int, char *, char *); +extern void untyped_lhs(void); +extern void untyped_rhs(int, char *); +extern void unknown_rhs(int); +extern void default_action_warning(void); +extern void undefined_goal(char *); +extern void undefined_symbol_warning(char *); + +extern void lalr(void); + +extern void reader(void); +extern void lr0(void); +extern void free_nullable(void); +extern void free_derives(void); +extern void make_parser(void); +extern void verbose(void); +extern void output(void); +extern void free_parser(void); +extern void write_section(char *[]); + +extern void create_symbol_table(void); +extern void free_symbol_table(void); +extern void free_symbols(void); + + +/* system variables */ + +extern char *__progname; diff --git a/yacc/error.c b/yacc/error.c @@ -0,0 +1,323 @@ +/* $OpenBSD: error.c,v 1.14 2014/03/08 01:05:39 tedu Exp $ */ +/* $NetBSD: error.c,v 1.4 1996/03/19 03:21:32 jtc Exp $ */ + +/* + * 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. 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. + */ + +/* routines for printing error messages */ + +#include "defs.h" + + +void +fatal(char *msg) +{ + fprintf(stderr, "%s: %s\n", input_file_name, msg); + done(2); +} + + +void +no_space(void) +{ + fprintf(stderr, "%s: yacc is out of space\n", input_file_name); + done(2); +} + + +void +open_error(char *filename) +{ + fprintf(stderr, "%s: cannot open source file %s\n", + input_file_name, filename); + done(2); +} + +void +open_write_error(char *filename) +{ + fprintf(stderr, "%s: cannot open target file %s for writing\n", + input_file_name, filename); + done(2); +} + +void +unexpected_EOF(void) +{ + fprintf(stderr, "%s:%d: unexpected end-of-file\n", + input_file_name, lineno); + done(1); +} + + +void +print_pos(char *st_line, char *st_cptr) +{ + char *s; + + if (st_line == 0) + return; + for (s = st_line; *s != '\n'; ++s) { + if (isprint((unsigned char)*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); +} + +void +syntax_error(int st_lineno, char *st_line, char *st_cptr) +{ + fprintf(stderr, "%s:%d: syntax error\n", + input_file_name, st_lineno); + print_pos(st_line, st_cptr); + done(1); +} + +void +unterminated_comment(int c_lineno, char *c_line, char *c_cptr) +{ + fprintf(stderr, "%s:%d: unmatched /*\n", + input_file_name, c_lineno); + print_pos(c_line, c_cptr); + done(1); +} + +void +unterminated_string(int s_lineno, char *s_line, char *s_cptr) +{ + fprintf(stderr, "%s:%d:, unterminated string\n", + input_file_name, s_lineno); + print_pos(s_line, s_cptr); + done(1); +} + +void +unterminated_text(int t_lineno, char *t_line, char *t_cptr) +{ + fprintf(stderr, "%s:%d: unmatched %%{\n", + input_file_name, t_lineno); + print_pos(t_line, t_cptr); + done(1); +} + +void +unterminated_union(int u_lineno, char *u_line, char *u_cptr) +{ + fprintf(stderr, "%s:%d: unterminated %%union declaration\n", + input_file_name, u_lineno); + print_pos(u_line, u_cptr); + done(1); +} + +void +over_unionized(char *u_cptr) +{ + fprintf(stderr, "%s:%d: too many %%union declarations\n", + input_file_name, lineno); + print_pos(line, u_cptr); + done(1); +} + +void +illegal_tag(int t_lineno, char *t_line, char *t_cptr) +{ + fprintf(stderr, "%s:%d: illegal tag\n", + input_file_name, t_lineno); + print_pos(t_line, t_cptr); + done(1); +} + + +void +illegal_character(char *c_cptr) +{ + fprintf(stderr, "%s:%d: illegal character\n", + input_file_name, lineno); + print_pos(line, c_cptr); + done(1); +} + + +void +used_reserved(char *s) +{ + fprintf(stderr, "%s:%d: illegal use of reserved symbol %s\n", + input_file_name, lineno, s); + done(1); +} + +void +tokenized_start(char *s) +{ + fprintf(stderr, "%s:%d: the start symbol %s cannot be declared to be a token\n", + input_file_name, lineno, s); + done(1); +} + +void +retyped_warning(char *s) +{ + fprintf(stderr, "%s:%d: the type of %s has been redeclared\n", + input_file_name, lineno, s); +} + +void +reprec_warning(char *s) +{ + fprintf(stderr, "%s:%d: the precedence of %s has been redeclared\n", + input_file_name, lineno, s); +} + +void +revalued_warning(char *s) +{ + fprintf(stderr, "%s:%d: the value of %s has been redeclared\n", + input_file_name, lineno, s); +} + +void +terminal_start(char *s) +{ + fprintf(stderr, "%s:%d: the start symbol %s is a token\n", + input_file_name, lineno, s); + done(1); +} + +void +restarted_warning(void) +{ + fprintf(stderr, "%s:%d: the start symbol has been redeclared\n", + input_file_name, lineno); +} + +void +no_grammar(void) +{ + fprintf(stderr, "%s:%d: no grammar has been specified\n", + input_file_name, lineno); + done(1); +} + +void +terminal_lhs(int s_lineno) +{ + fprintf(stderr, "%s:%d: a token appears on the lhs of a production\n", + input_file_name, s_lineno); + done(1); +} + +void +prec_redeclared(void) +{ + fprintf(stderr, "%s:%d: conflicting %%prec specifiers\n", + input_file_name, lineno); +} + +void +unterminated_action(int a_lineno, char *a_line, char *a_cptr) +{ + fprintf(stderr, "%s:%d: unterminated action\n", + input_file_name, a_lineno); + print_pos(a_line, a_cptr); + done(1); +} + +void +dollar_warning(int a_lineno, int i) +{ + fprintf(stderr, "%s:%d: $%d references beyond the end of the current rule\n", + input_file_name, a_lineno, i); +} + +void +dollar_error(int a_lineno, char *a_line, char *a_cptr) +{ + fprintf(stderr, "%s:%d: illegal $-name\n", + input_file_name, a_lineno); + print_pos(a_line, a_cptr); + done(1); +} + + +void +untyped_lhs(void) +{ + fprintf(stderr, "%s:%d: $$ is untyped\n", + input_file_name, lineno); + done(1); +} + +void +untyped_rhs(int i, char *s) +{ + fprintf(stderr, "%s:%d: $%d (%s) is untyped\n", + input_file_name, lineno, i, s); + done(1); +} + +void +unknown_rhs(int i) +{ + fprintf(stderr, "%s:%d: $%d is untyped\n", + input_file_name, lineno, i); + done(1); +} + +void +default_action_warning(void) +{ + fprintf(stderr, "%s:%d: the default action assigns an undefined value to $$\n", + input_file_name, lineno); +} + +void +undefined_goal(char *s) +{ + fprintf(stderr, "%s: the start symbol %s is undefined\n", input_file_name, s); + done(1); +} + +void +undefined_symbol_warning(char *s) +{ + fprintf(stderr, "%s: the symbol %s is undefined\n", input_file_name, s); +} diff --git a/yacc/lalr.c b/yacc/lalr.c @@ -0,0 +1,601 @@ +/* $OpenBSD: lalr.c,v 1.17 2014/05/17 15:19:17 chl Exp $ */ +/* $NetBSD: lalr.c,v 1.4 1996/03/19 03:21:33 jtc Exp $ */ + +/* + * 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. 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. + */ + +#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(); +void set_state_table(void); +void set_accessing_symbol(void); +void set_shift_table(void); +void set_reduction_table(void); +void set_maxrhs(void); +void initialize_LA(void); +void set_goto_map(void); +void initialize_F(void); +void build_relations(void); +void compute_FOLLOWS(void); +void compute_lookaheads(void); +int map_goto(int, int); +void digraph(short **); +void add_lookback_edge(int, int, int); +void traverse(int); + +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; + +void +lalr(void) +{ + 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(); + free_derives(); + free_nullable(); +} + + +void +set_state_table(void) +{ + core *sp; + + state_table = NEW2(nstates, core *); + for (sp = first_state; sp; sp = sp->next) + state_table[sp->number] = sp; +} + + +void +set_accessing_symbol(void) +{ + core *sp; + + accessing_symbol = NEW2(nstates, short); + for (sp = first_state; sp; sp = sp->next) + accessing_symbol[sp->number] = sp->accessing_symbol; +} + + +void +set_shift_table(void) +{ + shifts *sp; + + shift_table = NEW2(nstates, shifts *); + for (sp = first_shift; sp; sp = sp->next) + shift_table[sp->number] = sp; +} + + +void +set_reduction_table(void) +{ + reductions *rp; + + reduction_table = NEW2(nstates, reductions *); + for (rp = first_reduction; rp; rp = rp->next) + reduction_table[rp->number] = rp; +} + + +void +set_maxrhs(void) +{ + short *itemp, *item_end; + int length, 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; +} + + +void +initialize_LA(void) +{ + int i, j, k; + 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++; + } + } + } +} + +void +set_goto_map(void) +{ + shifts *sp; + int i, k, symbol; + int state1, state2; + short *temp_map; + + 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(int state, int symbol) +{ + int high, low, middle, 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; + } +} + + +void +initialize_F(void) +{ + int i, j, k; + shifts *sp; + short *edge, *rp, **reads; + unsigned int *rowp; + int nedges, stateno, symbol, 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); +} + + +void +build_relations(void) +{ + int i, j, k; + short *rulep, *rp; + shifts *sp; + int length, nedges, done; + int state1, stateno, symbol1, symbol2; + short *shortp, *edge, *states; + 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); +} + +void +add_lookback_edge(int stateno, int ruleno, int gotono) +{ + int i, k, found; + 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(short **R, int n) +{ + short **new_R, **temp_R, *nedges, *sp; + int i, 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); +} + + +void +compute_FOLLOWS(void) +{ + digraph(includes); +} + +void +compute_lookaheads(void) +{ + int i, n; + unsigned int *fp1, *fp2, *fp3; + shorts *sp, *next; + unsigned int *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); +} + +void +digraph(short **relation) +{ + int i; + + infinity = ngotos + 2; + INDEX = NEW2(ngotos + 1, short); + VERTICES = NEW2(ngotos + 1, short); + top = 0; + R = relation; + + memset(INDEX, 0, ngotos * sizeof(short)); + for (i = 0; i < ngotos; i++) + if (R[i]) + traverse(i); + + free(INDEX); + free(VERTICES); +} + + +void +traverse(int i) +{ + unsigned int *base, *fp1, *fp2, *fp3; + int j, height; + short *rp; + + 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/yacc/lr0.c b/yacc/lr0.c @@ -0,0 +1,504 @@ +/* $OpenBSD: lr0.c,v 1.18 2014/03/13 01:18:22 tedu Exp $ */ +/* $NetBSD: lr0.c,v 1.4 1996/03/19 03:21:35 jtc Exp $ */ + +/* + * 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. 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. + */ + +#include "defs.h" + +extern short *itemset; +extern short *itemsetend; +extern unsigned *ruleset; + +int nstates; +core *first_state; +shifts *first_shift; +reductions *first_reduction; + +short get_state(int); +core *new_state(int); + +void allocate_itemsets(void); +void allocate_storage(void); +void append_states(void); +void free_storage(void); +void generate_states(void); +void initialize_states(void); +void new_itemsets(void); +void save_shifts(void); +void save_reductions(void); +void set_derives(void); +void print_derives(void); +void set_nullable(void); + +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; + +void +allocate_itemsets(void) +{ + short *itemp, *item_end; + int i, count, max, symbol; + 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 *); +} + +void +allocate_storage(void) +{ + allocate_itemsets(); + shiftset = NEW2(nsyms, short); + redset = NEW2(nrules + 1, short); + state_set = NEW2(nitems, core *); +} + +void +append_states(void) +{ + int i, j, 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); + } +} + +void +free_storage(void) +{ + free(shift_symbol); + free(redset); + free(shiftset); + free(kernel_base); + free(kernel_end); + free(kernel_items); + free(state_set); +} + + +void +generate_states(void) +{ + 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(); +} + + + +short +get_state(int symbol) +{ + int n, found, key; + short *isp1, *isp2, *iend; + core *sp; + +#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); +} + + +void +initialize_states(void) +{ + int i; + short *start_derives; + core *p; + + start_derives = derives[start_symbol]; + for (i = 0; start_derives[i] >= 0; ++i) + continue; + + p = malloc(sizeof(core) + i * sizeof(short)); + if (p == NULL) + 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; +} + +void +new_itemsets(void) +{ + int i, shiftcount; + short *isp, *ksp; + int symbol; + + memset(kernel_end, 0, nsyms * sizeof(short *)); + + 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(int symbol) +{ + int n; + core *p; + short *isp1, *isp2, *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 = allocate(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); +} + + +void +save_shifts(void) +{ + shifts *p; + short *sp1, *sp2, *send; + + p = allocate(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; + } +} + + +void +save_reductions(void) +{ + short *isp, *rp1, *rp2; + int item, count; + reductions *p; + short *rend; + + count = 0; + for (isp = itemset; isp < itemsetend; isp++) { + item = ritem[*isp]; + if (item < 0) { + redset[count++] = -item; + } + } + + if (count) { + p = allocate(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; + } + } +} + +void +set_derives(void) +{ + int i, k, lhs; + 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 +} + +void +free_derives(void) +{ + free(derives[start_symbol]); + free(derives); +} + +#ifdef DEBUG +void +print_derives(void) +{ + int i; + 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 + +void +set_nullable(void) +{ + int i, j; + int empty; + int done; + + nullable = calloc(1, nsyms); + if (nullable == NULL) + no_space(); + + 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 +} + +void +free_nullable(void) +{ + free(nullable); +} + +void +lr0(void) +{ + set_derives(); + set_nullable(); + generate_states(); +} diff --git a/yacc/main.c b/yacc/main.c @@ -0,0 +1,362 @@ +/* $OpenBSD: main.c,v 1.26 2014/03/13 00:33:55 tedu Exp $ */ +/* $NetBSD: main.c,v 1.5 1996/03/19 03:21:38 jtc Exp $ */ + +/* + * 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. 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. + */ + +#include <sys/types.h> +#include <fcntl.h> +#include <paths.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> +#include "defs.h" + +char dflag; +char lflag; +char rflag; +char tflag; +char vflag; + +char *symbol_prefix; +char *file_prefix = "y"; + +int lineno; +int outline; + +int explicit_file_name; + +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; + +void onintr(int); +void set_signals(void); +void usage(void); +void getargs(int, char *[]); +void create_file_names(void); +void open_files(void); + +volatile sig_atomic_t sigdie; + +void +done(int k) +{ + if (action_file) + unlink(action_file_name); + if (text_file) + unlink(text_file_name); + if (union_file) + unlink(union_file_name); + if (sigdie) + _exit(k); + exit(k); +} + + +void +onintr(int signo) +{ + sigdie = 1; + done(1); +} + + +void +set_signals(void) +{ +#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 +} + + +void +usage(void) +{ + fprintf(stderr, "usage: %s [-dlrtv] [-b file_prefix] [-o output_file] [-p symbol_prefix] file\n", __progname); + exit(1); +} + + +void +getargs(int argc, char *argv[]) +{ + int ch; + + while ((ch = getopt(argc, argv, "b:dlo:p:rtv")) != -1) { + switch (ch) { + case 'b': + file_prefix = optarg; + break; + + case 'd': + dflag = 1; + break; + + case 'l': + lflag = 1; + break; + + case 'o': + output_file_name = optarg; + explicit_file_name = 1; + break; + + case 'p': + symbol_prefix = optarg; + break; + + case 'r': + rflag = 1; + break; + + case 't': + tflag = 1; + break; + + case 'v': + vflag = 1; + break; + + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + if (strcmp(*argv, "-") == 0) + input_file = stdin; + else + input_file_name = *argv; +} + + +void * +allocate(size_t n) +{ + void *v; + + v = NULL; + if (n) { + v = calloc(1, n); + if (!v) + no_space(); + } + return (v); +} + +#define TEMPNAME(s, c, d, l) \ + (asprintf(&(s), "%.*s/yacc.%xXXXXXXXXXX", (int)(l), (d), (c))) + +void +create_file_names(void) +{ + size_t len; + char *tmpdir; + + if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') + tmpdir = _PATH_TMP; + + len = strlen(tmpdir); + if (tmpdir[len - 1] == '/') + len--; + + if (TEMPNAME(action_file_name, 'a', tmpdir, len) == -1 || + TEMPNAME(text_file_name, 'r', tmpdir, len) == -1 || + TEMPNAME(union_file_name, 'u', tmpdir, len) == -1) + no_space(); + + if (output_file_name == NULL) { + if (asprintf(&output_file_name, "%s%s", file_prefix, OUTPUT_SUFFIX) + == -1) + no_space(); + } + if (rflag) { + if (asprintf(&code_file_name, "%s%s", file_prefix, CODE_SUFFIX) == -1) + no_space(); + } else + code_file_name = output_file_name; + + if (dflag) { + if (explicit_file_name) { + char *suffix; + + defines_file_name = strdup(output_file_name); + if (defines_file_name == 0) + no_space(); + + /* does the output_file_name have a known suffix */ + if ((suffix = strrchr(output_file_name, '.')) != 0 && + (!strcmp(suffix, ".c") || /* good, old-fashioned C */ + !strcmp(suffix, ".C") || /* C++, or C on Windows */ + !strcmp(suffix, ".cc") || /* C++ */ + !strcmp(suffix, ".cxx") || /* C++ */ + !strcmp(suffix, ".cpp"))) {/* C++ (Windows) */ + strncpy(defines_file_name, output_file_name, + suffix - output_file_name + 1); + defines_file_name[suffix - output_file_name + 1] = 'h'; + defines_file_name[suffix - output_file_name + 2] = '\0'; + } else { + fprintf(stderr, "%s: suffix of output file name %s" + " not recognized, no -d file generated.\n", + __progname, output_file_name); + dflag = 0; + free(defines_file_name); + defines_file_name = 0; + } + } else { + if (asprintf(&defines_file_name, "%s%s", file_prefix, + DEFINES_SUFFIX) == -1) + no_space(); + } + } + if (vflag) { + if (asprintf(&verbose_file_name, "%s%s", file_prefix, + VERBOSE_SUFFIX) == -1) + no_space(); + } +} + + +void +open_files(void) +{ + int fd; + + create_file_names(); + + if (input_file == 0) { + input_file = fopen(input_file_name, "r"); + if (input_file == 0) + open_error(input_file_name); + } + fd = mkstemp(action_file_name); + if (fd == -1 || (action_file = fdopen(fd, "w")) == NULL) + open_error(action_file_name); + + fd = mkstemp(text_file_name); + if (fd == -1 || (text_file = fdopen(fd, "w")) == NULL) + 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 == NULL) + open_write_error(defines_file_name); + fd = mkstemp(union_file_name); + if (fd == -1 || (union_file = fdopen(fd, "w")) == NULL) + 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(int argc, char *argv[]) +{ + set_signals(); + getargs(argc, argv); + open_files(); + reader(); + lr0(); + lalr(); + make_parser(); + verbose(); + output(); + done(0); + /* NOTREACHED */ + return (0); +} diff --git a/yacc/mkpar.c b/yacc/mkpar.c @@ -0,0 +1,370 @@ +/* $OpenBSD: mkpar.c,v 1.18 2014/03/13 00:59:34 tedu Exp $ */ +/* $NetBSD: mkpar.c,v 1.4 1996/03/19 03:21:39 jtc Exp $ */ + +/* + * 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. 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. + */ + +#include "defs.h" + +action **parser; +int SRtotal; +int SRexpect = 0; +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(); + +short sole_reduction(int); +void free_action_row(action *); + +void find_final_state(void); +void unused_rules(void); +void remove_conflicts(void); +void total_conflicts(void); +void defreds(void); + + +void +make_parser(void) +{ + 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(int stateno) +{ + action *actions; + + actions = get_shifts(stateno); + actions = add_reductions(stateno, actions); + return (actions); +} + + +action * +get_shifts(int stateno) +{ + action *actions, *temp; + shifts *sp; + short *to_state; + int i, k; + 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(int stateno, action * actions) +{ + int i, j, m, n; + int ruleno, tokensetsize; + 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(action * actions, int ruleno, int symbol) +{ + 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); +} + + +void +find_final_state(void) +{ + int goal, i; + short *to_state; + 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; + } +} + + +void +unused_rules(void) +{ + int i; + action *p; + + rules_used = calloc(nrules, sizeof(short)); + if (rules_used == NULL) + no_space(); + + 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", __progname); + else + fprintf(stderr, "%s: %d rules never reduced\n", __progname, + nunused); + } +} + + +void +remove_conflicts(void) +{ + int i; + int symbol; + action *p, *pref = NULL; + + 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; + } +} + + +void +total_conflicts(void) +{ + /* Warn if s/r != expect or if any r/r */ + if ((SRtotal != SRexpect) || RRtotal) { + if (SRtotal == 1) + fprintf(stderr, "%s: %s finds 1 shift/reduce conflict\n", + input_file_name, __progname); + else if (SRtotal > 1) + fprintf(stderr, "%s: %s finds %d shift/reduce conflicts\n", + input_file_name, __progname, SRtotal); + } + if (RRtotal == 1) + fprintf(stderr, "%s: %s finds 1 reduce/reduce conflict\n", + input_file_name, __progname); + else if (RRtotal > 1) + fprintf(stderr, "%s: %s finds %d reduce/reduce conflicts\n", + input_file_name, __progname, RRtotal); +} + + +short +sole_reduction(int stateno) +{ + int count; + short ruleno; + 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); +} + + +void +defreds(void) +{ + int i; + + defred = NEW2(nstates, short); + for (i = 0; i < nstates; i++) + defred[i] = sole_reduction(i); +} + +void +free_action_row(action * p) +{ + action *q; + + while (p) { + q = p->next; + free(p); + p = q; + } +} + +void +free_parser(void) +{ + int i; + + for (i = 0; i < nstates; i++) + free_action_row(parser[i]); + + free(parser); +} diff --git a/yacc/output.c b/yacc/output.c @@ -0,0 +1,1205 @@ +/* $OpenBSD: output.c,v 1.23 2014/03/13 01:18:22 tedu Exp $ */ +/* $NetBSD: output.c,v 1.4 1996/03/19 03:21:41 jtc Exp $ */ + +/* + * 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. 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. + */ + +#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; + +void output_prefix(void); +void output_rule_data(void); +void output_yydefred(void); +void output_actions(void); +void token_actions(void); +void goto_actions(void); +int default_goto(int); +void save_column(int, int); +void sort_actions(void); +void pack_table(void); +int matching_vector(int); +int pack_vector(int); +void output_base(void); +void output_table(void); +void output_check(void); +int is_C_identifier(char *); +void output_defines(void); +void output_stored_text(void); +void output_debug(void); +void output_stype(void); +void output_trailing_text(void); +void output_semantic_actions(void); +void free_itemsets(void); +void free_shifts(void); +void free_reductions(void); + +void +output(void) +{ + 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); +} + + +void +output_prefix(void) +{ + 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 yysslim %ssslim\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 yystacksize %sstacksize\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); +} + + +void +output_rule_data(void) +{ + int i; + int j; + + fprintf(output_file, + "const short %slhs[] =\n" + "\t{%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, + "const short %slen[] =\n" + "\t{%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"); +} + + +void +output_yydefred(void) +{ + int i, j; + + fprintf(output_file, + "const short %sdefred[] =\n" + "\t{%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"); +} + + +void +output_actions(void) +{ + 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(); +} + + +void +token_actions(void) +{ + int i, j; + int shiftcount, reducecount; + int max, min; + short *actionrow, *r, *s; + 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); +} + +void +goto_actions(void) +{ + int i, j, k; + + state_count = NEW2(nstates, short); + + k = default_goto(start_symbol + 1); + fprintf(output_file, "const short %sdgoto[] =\n" + "\t{%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(int symbol) +{ + int i; + int m; + int n; + int default_state; + int max; + + m = goto_map[symbol]; + n = goto_map[symbol + 1]; + + if (m == n) + return (0); + + memset(state_count, 0, nstates * sizeof(short)); + + 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); +} + + + +void +save_column(int symbol, int default_state) +{ + int i; + int m; + int n; + short *sp; + short *sp1; + short *sp2; + int count; + 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; +} + +void +sort_actions(void) +{ + int i; + int j; + int k; + int t; + 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++; + } + } +} + + +void +pack_table(void) +{ + int i; + int place; + 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(int vector) +{ + int i, j, k, t, w, match, 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(int vector) +{ + int i, j, k, l; + int t, loc, ok; + short *from, *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 = realloc(table, newmax * sizeof(short)); + if (table == NULL) + no_space(); + check = realloc(check, newmax * sizeof(short)); + if (check == NULL) + 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); + } + } +} + + + +void +output_base(void) +{ + int i, j; + + fprintf(output_file, "const short %ssindex[] =\n" + "\t{%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" + "const short %srindex[] =\n" + "\t{%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" + "const short %sgindex[] =\n" + "\t{%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); +} + + +void +output_table(void) +{ + int i, j; + + ++outline; + fprintf(code_file, "#define YYTABLESIZE %d\n", high); + fprintf(output_file, "const short %stable[] =\n" + "\t{%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); +} + + +void +output_check(void) +{ + int i, j; + + fprintf(output_file, "const short %scheck[] =\n" + "\t{%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(char *name) +{ + char *s; + int c; + + s = name; + c = (unsigned char)*s; + if (c == '"') { + c = (unsigned char)*++s; + if (!isalpha(c) && c != '_' && c != '$') + return (0); + while ((c = (unsigned char)*++s) != '"') { + if (!isalnum(c) && c != '_' && c != '$') + return (0); + } + return (1); + } + + if (!isalpha(c) && c != '_' && c != '$') + return (0); + while ((c = (unsigned char)*++s)) { + if (!isalnum(c) && c != '_' && c != '$') + return (0); + } + return (1); +} + + +void +output_defines(void) +{ + int c, i; + 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 = (unsigned char)*s; + if (c == '"') { + while ((c = (unsigned char)*++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 = (unsigned char)*++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;\n"); + fprintf(defines_file, "#endif /* YYSTYPE_DEFINED */\n"); + fprintf(defines_file, "extern YYSTYPE %slval;\n", + symbol_prefix); + } +} + + +void +output_stored_text(void) +{ + int c; + 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); +} + + +void +output_debug(void) +{ + 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 = calloc(max+1, sizeof(char *)); + if (symnam == NULL) + no_space(); + + 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\n" + "const char * const %sname[] =\n" + "\t{", symbol_prefix); + j = 80; + for (i = 0; i <= max; ++i) { + if ((s = symnam[i]) != '\0') { + 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, + "const char * const %srule[] =\n" + "\t{", 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"); +} + + +void +output_stype(void) +{ + if (!unionized && ntags == 0) { + outline += 3; + fprintf(code_file, "#ifndef YYSTYPE\ntypedef int YYSTYPE;\n#endif\n"); + } +} + + +void +output_trailing_text(void) +{ + int c, last; + FILE *in, *out; + + if (line == 0) + return; + + in = input_file; + out = code_file; + c = (unsigned char)*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 = (unsigned char)*++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); +} + + +void +output_semantic_actions(void) +{ + int c, last; + 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); +} + + +void +free_itemsets(void) +{ + core *cp, *next; + + free(state_table); + for (cp = first_state; cp; cp = next) { + next = cp->next; + free(cp); + } +} + + +void +free_shifts(void) +{ + shifts *sp, *next; + + free(shift_table); + for (sp = first_shift; sp; sp = next) { + next = sp->next; + free(sp); + } +} + + + +void +free_reductions(void) +{ + reductions *rp, *next; + + free(reduction_table); + for (rp = first_reduction; rp; rp = next) { + next = rp->next; + free(rp); + } +} diff --git a/yacc/reader.c b/yacc/reader.c @@ -0,0 +1,1858 @@ +/* $OpenBSD: reader.c,v 1.29 2014/10/09 03:02:18 deraadt Exp $ */ +/* $NetBSD: reader.c,v 1.5 1996/03/19 03:21:43 jtc Exp $ */ + +/* + * 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. 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. + */ + +#include "defs.h" +#include "util.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 accommodate 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; + +void cachec(int); +void get_line(void); +char *dup_line(void); +void skip_comment(void); +int nextc(void); +int keyword(void); +void copy_ident(void); +void copy_text(void); +void copy_union(void); +bucket *get_literal(void); +int is_reserved(char *); +bucket *get_name(void); +int get_number(void); +char *get_tag(void); +void declare_tokens(int); +void declare_types(void); +void declare_start(void); +void handle_expect(void); +void read_declarations(void); +void initialize_grammar(void); +void expand_items(void); +void expand_rules(void); +void advance_to_start(void); +void start_rule(bucket *, int); +void end_rule(void); +void insert_empty_rule(void); +void add_symbol(void); +void copy_action(void); +int mark_symbol(void); +void read_grammar(void); +void free_tags(void); +void pack_names(void); +void check_symbols(void); +void pack_symbols(void); +void pack_grammar(void); +void print_grammar(void); + +char line_format[] = "#line %d \"%s\"\n"; + +void +cachec(int c) +{ + assert(cinc >= 0); + if (cinc >= cache_size) { + cache_size += 256; + cache = realloc(cache, cache_size); + if (cache == NULL) + no_space(); + } + cache[cinc] = c; + ++cinc; +} + + +void +get_line(void) +{ + FILE *f = input_file; + int c, i; + + if (saw_eof || (c = getc(f)) == EOF) { + if (line) { + free(line); + line = 0; + } + cptr = 0; + saw_eof = 1; + return; + } + if (line == NULL || linesize != (LINESIZE + 1)) { + if (line) + free(line); + linesize = LINESIZE + 1; + line = malloc(linesize); + if (line == NULL) + 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 == NULL) + no_space(); + } + c = getc(f); + if (c == EOF) { + line[i] = '\n'; + saw_eof = 1; + cptr = line; + return; + } + } +} + + +char * +dup_line(void) +{ + char *p, *s, *t; + + if (line == NULL) + return (0); + s = line; + while (*s != '\n') + ++s; + p = malloc(s - line + 1); + if (p == NULL) + no_space(); + + s = line; + t = p; + while ((*t++ = *s++) != '\n') + continue; + return (p); +} + + +void +skip_comment(void) +{ + 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 == NULL) + unterminated_comment(st_lineno, st_line, st_cptr); + s = cptr; + } else + ++s; + } +} + + +int +nextc(void) +{ + char *s; + + if (line == NULL) { + get_line(); + if (line == NULL) + return (EOF); + } + s = cptr; + for (;;) { + switch (*s) { + case '\n': + get_line(); + if (line == NULL) + 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 == NULL) + return (EOF); + s = cptr; + break; + } + /* fall through */ + + default: + cptr = s; + return ((unsigned char) *s); + } + } +} + + +int +keyword(void) +{ + int c; + char *t_cptr = cptr; + + c = (unsigned char) *++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 = (unsigned char) *++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); + if (strcmp(cache, "expect") == 0) + return (EXPECT); + } 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 */ + return (0); +} + + +void +copy_ident(void) +{ + int c; + FILE *f = output_file; + + c = nextc(); + if (c == EOF) + unexpected_EOF(); + if (c != '"') + syntax_error(lineno, line, cptr); + ++outline; + fprintf(f, "#ident \""); + for (;;) { + c = (unsigned char) *++cptr; + if (c == '\n') { + fprintf(f, "\"\n"); + return; + } + putc(c, f); + if (c == '"') { + putc('\n', f); + ++cptr; + return; + } + } +} + + +void +copy_text(void) +{ + int c; + int quote; + 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 == NULL) + unterminated_text(t_lineno, t_line, t_cptr); + } + if (!lflag) + fprintf(f, line_format, lineno, input_file_name); + +loop: + c = (unsigned char) *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 = (unsigned char) *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 = (unsigned char) *cptr++; + putc(c, f); + if (c == '\n') { + get_line(); + if (line == NULL) + unterminated_string(s_lineno, s_line, s_cptr); + } + } + } + } + + case '/': + putc(c, f); + need_newline = 1; + c = (unsigned char) *cptr; + if (c == '/') { + putc('*', f); + while ((c = (unsigned char) *++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 = (unsigned char) *cptr++; + putc(c, f); + if (c == '*' && *cptr == '/') { + putc('/', f); + ++cptr; + free(c_line); + goto loop; + } + if (c == '\n') { + get_line(); + if (line == NULL) + 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; + } +} + + +void +copy_union(void) +{ + int c, quote, 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, "#ifndef YYSTYPE_DEFINED\n"); + fprintf(text_file, "#define YYSTYPE_DEFINED\n"); + fprintf(text_file, "typedef union"); + if (dflag) + fprintf(union_file, "#ifndef YYSTYPE_DEFINED\n"); + if (dflag) + fprintf(union_file, "#define YYSTYPE_DEFINED\n"); + if (dflag) + fprintf(union_file, "typedef union"); + + depth = 0; +loop: + c = (unsigned char) *cptr++; + putc(c, text_file); + if (dflag) + putc(c, union_file); + switch (c) { + case '\n': +next_line: + get_line(); + if (line == NULL) + unterminated_union(u_lineno, u_line, u_cptr); + goto loop; + + case '{': + ++depth; + goto loop; + + case '}': + if (--depth == 0) { + fprintf(text_file, " YYSTYPE;\n"); + fprintf(text_file, "#endif /* YYSTYPE_DEFINED */\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 = (unsigned char) *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 = (unsigned char) *cptr++; + putc(c, text_file); + if (dflag) + putc(c, union_file); + if (c == '\n') { + get_line(); + if (line == NULL) + unterminated_string(s_lineno, + s_line, s_cptr); + } + } + } + } + + case '/': + c = (unsigned char) *cptr; + if (c == '/') { + putc('*', text_file); + if (dflag) + putc('*', union_file); + while ((c = (unsigned char) *++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 = (unsigned char) *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 == NULL) + unterminated_comment(c_lineno, + c_line, c_cptr); + } + } + } + goto loop; + + default: + goto loop; + } +} + + +bucket * +get_literal(void) +{ + int c, quote, i, n; + char *s; + bucket *bp; + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line); + + quote = (unsigned char) *cptr++; + cinc = 0; + for (;;) { + c = (unsigned char) *cptr++; + if (c == quote) + break; + if (c == '\n') + unterminated_string(s_lineno, s_line, s_cptr); + if (c == '\\') { + char *c_cptr = cptr - 1; + unsigned long ulval; + + c = (unsigned char) *cptr++; + switch (c) { + case '\n': + get_line(); + if (line == NULL) + 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': + ulval = strtoul(cptr - 1, &s, 8); + if (s == cptr - 1 || ulval > MAXCHAR) + illegal_character(c_cptr); + c = (int) ulval; + cptr = s; + break; + + case 'x': + ulval = strtoul(cptr, &s, 16); + if (s == cptr || ulval > MAXCHAR) + illegal_character(c_cptr); + c = (int) ulval; + cptr = s; + 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 == NULL) + no_space(); + + memcpy(s, cache, n); + + 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(char *name) +{ + char *s; + + if (strcmp(name, ".") == 0 || + strcmp(name, "$accept") == 0 || + strcmp(name, "$end") == 0) + return (1); + + if (name[0] == '$' && name[1] == '$' && isdigit((unsigned char) name[2])) { + s = name + 3; + while (isdigit((unsigned char) *s)) + ++s; + if (*s == NUL) + return (1); + } + return (0); +} + + +bucket * +get_name(void) +{ + int c; + + cinc = 0; + for (c = (unsigned char) *cptr; IS_IDENT(c); c = (unsigned char) *++cptr) + cachec(c); + cachec(NUL); + + if (is_reserved(cache)) + used_reserved(cache); + + return (lookup(cache)); +} + + +int +get_number(void) +{ + int c, n; + + n = 0; + for (c = (unsigned char) *cptr; isdigit(c); c = (unsigned char) *++cptr) + n = 10 * n + (c - '0'); + + return (n); +} + + +char * +get_tag(void) +{ + int c, i; + 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 = (unsigned char) *++cptr; + } while (IS_IDENT(c)); + cachec(NUL); + + c = nextc(); + if (c == EOF) + unexpected_EOF(); + if (c != '>') + illegal_tag(t_lineno, t_line, t_cptr); + free(t_line); + ++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 = reallocarray(tag_table, tagmax, sizeof(char *)); + if (tag_table == NULL) + no_space(); + } + s = malloc(cinc); + if (s == NULL) + no_space(); + strlcpy(s, cache, cinc); + tag_table[ntags] = s; + ++ntags; + return (s); +} + + +void +declare_tokens(int assoc) +{ + int c; + 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(); + } + } +} + + +/* + * %expect requires special handling as it really isn't part of the yacc + * grammar only a flag for yacc proper. + */ +void +declare_expect(int assoc) +{ + int c; + + if (assoc != EXPECT) + ++prec; + + /* + * Stay away from nextc - doesn't detect EOL and will read to EOF. + */ + c = (unsigned char) *++cptr; + if (c == EOF) + unexpected_EOF(); + + for (;;) { + if (isdigit(c)) { + SRexpect = get_number(); + break; + } + /* + * Looking for number before EOL. + * Spaces, tabs, and numbers are ok. + * Words, punc., etc. are syntax errors. + */ + else if (c == '\n' || isalpha(c) || !isspace(c)) { + syntax_error(lineno, line, cptr); + } else { + c = (unsigned char) *++cptr; + if (c == EOF) + unexpected_EOF(); + } + } +} + + +void +declare_types(void) +{ + int c; + 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; + } +} + + +void +declare_start(void) +{ + int c; + 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; +} + + +void +read_declarations(void) +{ + int c, k; + + cache_size = 256; + cache = malloc(cache_size); + if (cache == NULL) + 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 EXPECT: + declare_expect(k); + break; + + case TYPE: + declare_types(); + break; + + case START: + declare_start(); + break; + } + } +} + + +void +initialize_grammar(void) +{ + nitems = 4; + maxitems = 300; + pitem = calloc(maxitems, sizeof(bucket *)); + if (pitem == NULL) + no_space(); + + nrules = 3; + maxrules = 100; + plhs = reallocarray(NULL, maxrules, sizeof(bucket *)); + if (plhs == NULL) + no_space(); + plhs[0] = 0; + plhs[1] = 0; + plhs[2] = 0; + rprec = reallocarray(NULL, maxrules, sizeof(short)); + if (rprec == NULL) + no_space(); + rprec[0] = 0; + rprec[1] = 0; + rprec[2] = 0; + rassoc = reallocarray(NULL, maxrules, sizeof(char)); + if (rassoc == NULL) + no_space(); + rassoc[0] = TOKEN; + rassoc[1] = TOKEN; + rassoc[2] = TOKEN; +} + + +void +expand_items(void) +{ + int olditems = maxitems; + + maxitems += 300; + pitem = reallocarray(pitem, maxitems, sizeof(bucket *)); + if (pitem == NULL) + no_space(); + memset(pitem + olditems, 0, (maxitems - olditems) * sizeof(bucket *)); +} + + +void +expand_rules(void) +{ + maxrules += 100; + plhs = reallocarray(plhs, maxrules, sizeof(bucket *)); + if (plhs == NULL) + no_space(); + rprec = reallocarray(rprec, maxrules, sizeof(short)); + if (rprec == NULL) + no_space(); + rassoc = reallocarray(rassoc, maxrules, sizeof(char)); + if (rassoc == NULL) + no_space(); +} + + +void +advance_to_start(void) +{ + int c; + 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 == NULL) { + 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; +} + + +void +start_rule(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; +} + + +void +end_rule(void) +{ + int i; + + if (!last_was_action && plhs[nrules]->tag) { + for (i = nitems - 1; pitem[i]; --i) + continue; + if (i == maxitems - 1 || 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; +} + + +void +insert_empty_rule(void) +{ + bucket *bp, **bpp; + + assert(cache); + snprintf(cache, cache_size, "$$%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; +} + + +void +add_symbol(void) +{ + int c; + bucket *bp; + int s_lineno = lineno; + + c = (unsigned char) *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; +} + + +void +copy_action(void) +{ + int c, i, n, depth, quote; + char *tag; + 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 = (unsigned char) *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 = (unsigned char) *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((unsigned char) 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 == NULL) + untyped_lhs(); + fprintf(f, "yyval.%s", tag); + } else + fprintf(f, "yyval"); + cptr += 2; + goto loop; + } else if (isdigit((unsigned char) 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 == NULL) + 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 = (unsigned char) *++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"); + free(a_line); + return; + + case '{': + ++depth; + goto loop; + + case '}': + if (--depth > 0) + goto loop; + fprintf(f, "\nbreak;\n"); + free(a_line); + return; + + case '\'': + case '"': { + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line - 1); + + quote = c; + for (;;) { + c = (unsigned char) *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 = (unsigned char) *cptr++; + putc(c, f); + if (c == '\n') { + get_line(); + if (line == NULL) + unterminated_string(s_lineno, s_line, s_cptr); + } + } + } + } + + case '/': + c = (unsigned char) *cptr; + if (c == '/') { + putc('*', f); + while ((c = (unsigned char) *++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 = (unsigned char) *cptr++; + putc(c, f); + if (c == '*' && *cptr == '/') { + putc('/', f); + ++cptr; + free(c_line); + goto loop; + } + if (c == '\n') { + get_line(); + if (line == NULL) + unterminated_comment(c_lineno, c_line, c_cptr); + } + } + } + goto loop; + + default: + goto loop; + } +} + + +int +mark_symbol(void) +{ + int c; + bucket *bp = NULL; + + c = (unsigned char) 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 = (unsigned char) 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); +} + + +void +read_grammar(void) +{ + 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(); +} + + +void +free_tags(void) +{ + int i; + + if (tag_table == NULL) + return; + + for (i = 0; i < ntags; ++i) { + assert(tag_table[i]); + free(tag_table[i]); + } + free(tag_table); +} + + +void +pack_names(void) +{ + bucket *bp; + 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 == NULL) + no_space(); + + strlcpy(name_pool, "$accept", name_pool_size); + strlcpy(name_pool + 8, "$end", name_pool_size - 8); + 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; + } +} + + +void +check_symbols(void) +{ + 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; + } + } +} + + +void +pack_symbols(void) +{ + bucket *bp; + bucket **v; + 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 = reallocarray(NULL, nsyms, sizeof(char *)); + if (symbol_name == NULL) + no_space(); + symbol_value = reallocarray(NULL, nsyms, sizeof(short)); + if (symbol_value == NULL) + no_space(); + symbol_prec = reallocarray(NULL, nsyms, sizeof(short)); + if (symbol_prec == NULL) + no_space(); + symbol_assoc = malloc(nsyms); + if (symbol_assoc == NULL) + no_space(); + + v = reallocarray(NULL, nsyms, sizeof(bucket *)); + if (v == NULL) + 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); +} + + +void +pack_grammar(void) +{ + int i, j; + int assoc, prec; + + ritem = reallocarray(NULL, nitems, sizeof(short)); + if (ritem == NULL) + no_space(); + rlhs = reallocarray(NULL, nrules, sizeof(short)); + if (rlhs == NULL) + no_space(); + rrhs = reallocarray(NULL, nrules + 1, sizeof(short)); + if (rrhs == NULL) + no_space(); + rprec = reallocarray(rprec, nrules, sizeof(short)); + if (rprec == NULL) + no_space(); + rassoc = realloc(rassoc, nrules); + if (rassoc == NULL) + 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); +} + + +void +print_grammar(void) +{ + int i, j, k; + int spacing = 0; + 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); + } +} + + +void +reader(void) +{ + 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/yacc/reallocarray.c b/yacc/reallocarray.c @@ -0,0 +1,38 @@ +/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */ +/* + * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); +} diff --git a/yacc/skeleton.c b/yacc/skeleton.c @@ -0,0 +1,404 @@ +/* $OpenBSD: skeleton.c,v 1.35 2014/03/16 18:38:30 guenther Exp $ */ +/* $NetBSD: skeleton.c,v 1.10 1996/03/25 00:36:18 mrg Exp $ */ + +/* + * 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. 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. + */ + +#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[] = +{ + "#include <stdlib.h>", + "#include <string.h>", + "#define YYBYACC 1", + "#define YYMAJOR 1", + "#define YYMINOR 9", + "#define YYLEX yylex()", + "#define YYEMPTY -1", + "#define yyclearin (yychar=(YYEMPTY))", + "#define yyerrok (yyerrflag=0)", + "#define YYRECOVERING() (yyerrflag!=0)", + NULL +}; + + +char *tables[] = +{ + "extern const short yylhs[];", + "extern const short yylen[];", + "extern const short yydefred[];", + "extern const short yydgoto[];", + "extern const short yysindex[];", + "extern const short yyrindex[];", + "extern const short yygindex[];", + "extern const short yytable[];", + "extern const short yycheck[];", + "#if YYDEBUG", + "extern const char *const yyname[];", + "extern const char *const yyrule[];", + "#endif", + NULL +}; + + +char *header[] = +{ + "#ifdef YYSTACKSIZE", + "#undef YYMAXDEPTH", + "#define YYMAXDEPTH YYSTACKSIZE", + "#else", + "#ifdef YYMAXDEPTH", + "#define YYSTACKSIZE YYMAXDEPTH", + "#else", + "#define YYSTACKSIZE 10000", + "#define YYMAXDEPTH 10000", + "#endif", + "#endif", + "#define YYINITSTACKSIZE 200", + "/* LINTUSED */", + "int yydebug;", + "int yynerrs;", + "int yyerrflag;", + "int yychar;", + "short *yyssp;", + "YYSTYPE *yyvsp;", + "YYSTYPE yyval;", + "YYSTYPE yylval;", + "short *yyss;", + "short *yysslim;", + "YYSTYPE *yyvs;", + "unsigned int yystacksize;", + NULL +}; + + +char *body[] = +{ + "/* allocate initial stack or double stack size, up to YYMAXDEPTH */", + "static int yygrowstack(void)", + "{", + " unsigned int newsize;", + " long sslen;", + " short *newss;", + " YYSTYPE *newvs;", + "", + " if ((newsize = yystacksize) == 0)", + " newsize = YYINITSTACKSIZE;", + " else if (newsize >= YYMAXDEPTH)", + " return -1;", + " else if ((newsize *= 2) > YYMAXDEPTH)", + " newsize = YYMAXDEPTH;", + " sslen = yyssp - yyss;", + "#ifdef SIZE_MAX", + "#define YY_SIZE_MAX SIZE_MAX", + "#else", + "#define YY_SIZE_MAX 0xffffffffU", + "#endif", + " if (newsize && YY_SIZE_MAX / newsize < sizeof *newss)", + " goto bail;", + " newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) :", + " (short *)malloc(newsize * sizeof *newss); /* overflow check above */", + " if (newss == NULL)", + " goto bail;", + " yyss = newss;", + " yyssp = newss + sslen;", + " if (newsize && YY_SIZE_MAX / newsize < sizeof *newvs)", + " goto bail;", + " newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) :", + " (YYSTYPE *)malloc(newsize * sizeof *newvs); /* overflow check above */", + " if (newvs == NULL)", + " goto bail;", + " yyvs = newvs;", + " yyvsp = newvs + sslen;", + " yystacksize = newsize;", + " yysslim = yyss + newsize - 1;", + " return 0;", + "bail:", + " if (yyss)", + " free(yyss);", + " if (yyvs)", + " free(yyvs);", + " yyss = yyssp = NULL;", + " yyvs = yyvsp = NULL;", + " yystacksize = 0;", + " return -1;", + "}", + "", + "#define YYABORT goto yyabort", + "#define YYREJECT goto yyabort", + "#define YYACCEPT goto yyaccept", + "#define YYERROR goto yyerrlab", + "int", + "yyparse(void)", + "{", + " int yym, yyn, yystate;", + "#if YYDEBUG", + " const char *yys;", + "", + " if ((yys = getenv(\"YYDEBUG\")))", + " {", + " yyn = *yys;", + " if (yyn >= '0' && yyn <= '9')", + " yydebug = yyn - '0';", + " }", + "#endif /* YYDEBUG */", + "", + " yynerrs = 0;", + " yyerrflag = 0;", + " yychar = (-1);", + "", + " if (yyss == NULL && yygrowstack()) goto yyoverflow;", + " yyssp = yyss;", + " yyvsp = yyvs;", + " *yyssp = yystate = 0;", + "", + "yyloop:", + " if ((yyn = yydefred[yystate]) != 0) 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 >= yysslim && yygrowstack())", + " {", + " 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;", + "#if defined(__GNUC__)", + " goto yynewerror;", + "#endif", + "yynewerror:", + " yyerror(\"syntax error\");", + "#if defined(__GNUC__)", + " 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 >= yysslim && yygrowstack())", + " {", + " 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];", + " if (yym)", + " yyval = yyvsp[1-yym];", + " else", + " memset(&yyval, 0, sizeof yyval);", + " switch (yyn)", + " {", + NULL +}; + + +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 >= yysslim && yygrowstack())", + " {", + " goto yyoverflow;", + " }", + " *++yyssp = yystate;", + " *++yyvsp = yyval;", + " goto yyloop;", + "yyoverflow:", + " yyerror(\"yacc stack overflow\");", + "yyabort:", + " if (yyss)", + " free(yyss);", + " if (yyvs)", + " free(yyvs);", + " yyss = yyssp = NULL;", + " yyvs = yyvsp = NULL;", + " yystacksize = 0;", + " return (1);", + "yyaccept:", + " if (yyss)", + " free(yyss);", + " if (yyvs)", + " free(yyvs);", + " yyss = yyssp = NULL;", + " yyvs = yyvsp = NULL;", + " yystacksize = 0;", + " return (0);", + "}", + NULL +}; + + +void +write_section(char *section[]) +{ + int i; + char *s; + + for (i = 0; (s = section[i]); ++i) { + ++outline; + fputs(s, code_file); + putc('\n', code_file); + } +} diff --git a/yacc/symtab.c b/yacc/symtab.c @@ -0,0 +1,151 @@ +/* $OpenBSD: symtab.c,v 1.17 2014/03/13 00:56:39 tedu Exp $ */ +/* $NetBSD: symtab.c,v 1.4 1996/03/19 03:21:48 jtc Exp $ */ + +/* + * 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. 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. + */ + +#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(char *); + + +int +hash(char *name) +{ + char *s; + 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(char *name) +{ + bucket *bp; + + assert(name); + bp = malloc(sizeof(bucket)); + if (bp == NULL) + no_space(); + bp->link = 0; + bp->next = 0; + bp->name = strdup(name); + if (bp->name == NULL) + no_space(); + bp->tag = 0; + bp->value = UNDEFINED; + bp->index = 0; + bp->prec = 0; + bp->class = UNKNOWN; + bp->assoc = TOKEN; + + return (bp); +} + + +bucket * +lookup(char *name) +{ + 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); +} + + +void +create_symbol_table(void) +{ + bucket *bp; + + symbol_table = calloc(TABLE_SIZE, sizeof(bucket *)); + if (symbol_table == NULL) + no_space(); + + bp = make_bucket("error"); + bp->index = 1; + bp->class = TERM; + + first_symbol = bp; + last_symbol = bp; + symbol_table[hash("error")] = bp; +} + + +void +free_symbol_table(void) +{ + free(symbol_table); + symbol_table = 0; +} + + +void +free_symbols(void) +{ + bucket *p, *q; + + for (p = first_symbol; p; p = q) { + q = p->next; + free(p); + } +} diff --git a/yacc/util.h b/yacc/util.h @@ -0,0 +1,3 @@ +#include <sys/stat.h> + +void *reallocarray(void *, size_t, size_t); diff --git a/yacc/verbose.c b/yacc/verbose.c @@ -0,0 +1,351 @@ +/* $OpenBSD: verbose.c,v 1.13 2014/10/09 03:02:18 deraadt Exp $ */ +/* $NetBSD: verbose.c,v 1.4 1996/03/19 03:21:50 jtc Exp $ */ + +/* + * 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. 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. + */ + +#include "defs.h" +#include "util.h" + +static short *null_rules; + +void log_unused(void); +void log_conflicts(void); +void print_state(int); +void print_conflicts(int); +void print_core(int); +void print_nulls(int); +void print_actions(int); +void print_shifts(action *); +void print_reductions(action *, int); +void print_gotos(int); + +void +verbose(void) +{ + int i; + + if (!vflag) + return; + + null_rules = reallocarray(NULL, nrules, sizeof(short)); + if (null_rules == NULL) + 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); +} + + +void +log_unused(void) +{ + int i; + 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); + } + } +} + + +void +log_conflicts(void) +{ + 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"); + } + } +} + + +void +print_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); +} + + +void +print_conflicts(int state) +{ + int symbol, act = REDUCE, number = 0; + 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]); + } + } + } + } +} + + +void +print_core(int state) +{ + int i; + int k; + int rule; + core *statep; + short *sp; + 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); + } +} + + +void +print_nulls(int state) +{ + action *p; + 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"); +} + + +void +print_actions(int stateno) +{ + action *p; + shifts *sp; + 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); + } +} + + +void +print_shifts(action * p) +{ + int count; + 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); + } + } +} + + +void +print_reductions(action * p, int defred) +{ + int k, anyreds; + 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); + } +} + + +void +print_gotos(int stateno) +{ + int i, k; + int as; + short *to_state; + 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/yacc/warshall.c b/yacc/warshall.c @@ -0,0 +1,100 @@ +/* $OpenBSD: warshall.c,v 1.11 2014/03/13 01:18:22 tedu Exp $ */ +/* $NetBSD: warshall.c,v 1.4 1996/03/19 03:21:51 jtc Exp $ */ + +/* + * 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. 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. + */ + +#include "defs.h" + +void transitive_closure(unsigned int *, int); + +void +transitive_closure(unsigned int *R, int n) +{ + int rowsize; + unsigned int i; + unsigned int *rowj, *rp, *rend, *ccol, *relend, *cword, *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; + } +} + +void +reflexive_transitive_closure(unsigned int *R, int n) +{ + int rowsize; + unsigned int i; + unsigned int *rp, *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/yacc/yacc.1 b/yacc/yacc.1 @@ -0,0 +1,256 @@ +.\" $OpenBSD: yacc.1,v 1.30 2014/06/04 06:55:50 jmc Exp $ +.\" +.\" 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. 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. +.\" +.\" from: @(#)yacc.1 5.7 (Berkeley) 7/30/91 +.\" +.Dd $Mdocdate: June 4 2014 $ +.Dt YACC 1 +.Os +.Sh NAME +.Nm yacc +.Nd an +.Tn LALR(1) +parser generator +.Sh SYNOPSIS +.Nm yacc +.Op Fl dlrtv +.Op Fl b Ar file_prefix +.Op Fl o Ar output_file +.Op Fl p Ar symbol_prefix +.Ar file +.Sh DESCRIPTION +.Nm +reads the grammar specification in +.Ar file +and generates an +.Tn LR(1) +parser for it. +The parsers consist of a set of +.Tn LALR(1) +parsing tables and a driver routine +written in the C programming language. +.Nm +normally writes the parse tables and the driver routine to the file +.Pa y.tab.c . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl b Ar file_prefix +The +.Fl b +option changes the prefix prepended to the output file names to +the string denoted by +.Ar file_prefix . +The default prefix is the character +.Ar y . +.It Fl d +The +.Fl d +option causes the header file +.Pa y.tab.h +to be written. +.It Fl l +If the +.Fl l +option is not specified, +.Nm +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 +.Fl l +option is specified, +.Nm +will not insert the #line directives. +#line directives specified by the user will be retained. +.It Fl o Ar output_file +The +.Fl o +option specifies an explicit name for the parser's output file name instead +of the default. +The names of the other output files are constructed from +.Pa output_file +as described under the +.Fl d +and +.Fl v +options. +.It Fl p Ar symbol_prefix +The +.Fl p +option changes the prefix prepended to yacc-generated symbols to +the string denoted by +.Ar symbol_prefix . +The default prefix is the string +.Ar yy . +.It Fl r +The +.Fl r +option causes +.Nm +to produce separate files for code and tables. +The code file is named +.Pa y.code.c , +and the tables file is named +.Pa y.tab.c . +.It Fl t +The +.Fl t +option changes the preprocessor directives generated by +.Nm +so that debugging statements will be incorporated in the compiled code. +.It Fl v +The +.Fl v +option causes a human-readable description of the generated parser to +be written to the file +.Pa y.output . +.El +.Sh ENVIRONMENT +.Bl -tag -width TMPDIR +.It Ev TMPDIR +Name of directory where temporary files are to be created. +.El +.Sh TABLES +The names of the tables generated by this version of +.Nm +are +.Dq yylhs , +.Dq yylen , +.Dq yydefred , +.Dq yydgoto , +.Dq yysindex , +.Dq yyrindex , +.Dq yygindex , +.Dq yytable , +and +.Dq yycheck . +Two additional tables, +.Dq yyname +and +.Dq yyrule , +are created if +.Dv YYDEBUG +is defined and non-zero. +.Sh FILES +.Bl -tag -width /tmp/yacc.uXXXXXXXXXX -compact +.It Pa y.code.c +.It Pa y.tab.c +.It Pa y.tab.h +.It Pa y.output +.It Pa /tmp/yacc.aXXXXXXXXXX +.It Pa /tmp/yacc.tXXXXXXXXXX +.It Pa /tmp/yacc.uXXXXXXXXXX +.El +.Sh EXIT STATUS +.Ex -std yacc +.Sh DIAGNOSTICS +If there are rules that are never reduced, the number of such rules is +written to the standard error. +If there are any +.Tn LALR(1) +conflicts, the number of conflicts is also written +to the standard error. +.Sh SEE ALSO +.Xr yyfix 1 +.Rs +.%A F. DeRemer +.%A T. J. Pennello +.%D 1982 +.%J TOPLAS +.%N Issue 4 +.%P pp. 615\(en649 +.%T Efficient Computation of LALR(1) Look-Ahead Sets +.%V Volume 4 +.Re +.Sh STANDARDS +The +.Nm +utility is compliant with the +.St -p1003.1-2008 +specification, +though its presence is optional. +.Pp +The flags +.Op Fl or , +as well as the environment variable +.Ev TMPDIR , +are extensions to that specification. +.Sh HISTORY +.Nm +was originally developed at AT&T by +.An Stephen C. Johnson . +.Pp +Berkeley +.Nm +was originally developed using PCC on a VAX with the +intent of being as compatible as possible with +.At +.Nm . +Much is owed to the unflagging efforts of Keith Bostic. +His badgering kept me working on +.Nm +long after I was ready to quit. +.Pp +Berkeley +.Nm +is based on the excellent algorithm for computing +LALR(1) lookaheads developed by +.An Tom Pennello +and +.An Frank DeRemer . +The algorithm is described in their almost impenetrable article in +TOPLAS (see above). +.Pp +Finally, much credit must go to those who pointed out deficiencies +of 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, +and +Parag Patel. +.Sh AUTHORS +The +.Nm +utility was written by +.An Robert Corbett . diff --git a/yacc/yyfix.1 b/yacc/yyfix.1 @@ -0,0 +1,108 @@ +.\" $OpenBSD: yyfix.1,v 1.6 2014/11/15 14:41:02 bentley Exp $ +.\" 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. 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. +.\" +.\" from: @(#)yyfix.1 5.4 (Berkeley) 3/23/93 +.\" +.Dd $Mdocdate: November 15 2014 $ +.Dt YYFIX 1 +.Os +.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 +.Pa :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 yacc +are different from those of historical versions of 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 1 , +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 1 . +.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 1 . +.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 first appeared in +.Bx 4.4 . diff --git a/yacc/yyfix.sh b/yacc/yyfix.sh @@ -0,0 +1,73 @@ +#!/bin/sh - +# +# $OpenBSD: yyfix.sh,v 1.3 2009/06/12 13:33:29 sobrado Exp $ +# 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. 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. +# +# from: @(#)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" + +if [ $# -eq 0 ]; then + echo "usage: `basename $0` file [tables]" >&2 + exit 1 +fi + +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