* Eliminate all shift/reduce conflicts in the grammar. This

requires that some ordering requirements are checked by the
  back-end C code instead of the parser (dirspecs, maxpart).

* Be more careful to require newline tokens in the grammer where
  they are expected, and deal with blank lines, etc.  This allows
  elimination of a trailing context on newline in the scanner.

* Let the parser set values for "needs-count" and "needs-flag"
  instead of making those special cases in the scanner.

* Get rid of '= ' preceeding actions (obsolete yacc syntax)

* Make the scanner not insert an extra newline after includes.
  (It was just an accidental side-effect of the ENDFILE stuff.)
This commit is contained in:
gwr 1996-11-11 23:54:17 +00:00
parent a65399dce0
commit a0b75afc0b
2 changed files with 147 additions and 195 deletions

View File

@ -1,5 +1,5 @@
%{
/* $NetBSD: gram.y,v 1.11 1996/11/07 22:59:42 gwr Exp $ */
/* $NetBSD: gram.y,v 1.12 1996/11/11 23:54:17 gwr Exp $ */
/*
* Copyright (c) 1992, 1993
@ -45,9 +45,8 @@
* from: @(#)gram.y 8.1 (Berkeley) 6/6/93
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@ -63,7 +62,6 @@
int include __P((const char *, int));
void yyerror __P((const char *));
int yylex __P((void));
extern const char *lastfile;
static struct config conf; /* at most one active at a time */
@ -86,10 +84,9 @@ static int adepth;
#define fx_and(e1, e2) new0(NULL, NULL, e1, FX_AND, e2)
#define fx_or(e1, e2) new0(NULL, NULL, e1, FX_OR, e2)
static void setupdirs __P((void));
static void cleanup __P((void));
static void setmachine __P((const char *, const char *));
static void setmaxpartitions __P((int));
static void check_maxpart __P((void));
%}
@ -105,11 +102,15 @@ static void setmaxpartitions __P((int));
%token AND AT ATTACH BUILD COMPILE_WITH CONFIG DEFINE DEVICE DUMPS ENDFILE
%token XFILE FLAGS INCLUDE XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS
%token MINOR ON OPTIONS PSEUDO_DEVICE ROOT SOURCE SWAP WITH
%token <val> FFLAG NUMBER
%token NEEDS_COUNT NEEDS_FLAG
%token <val> NUMBER
%token <str> PATHNAME WORD
%left '|'
%left '&'
%type <list> fopts fexpr fatom
%type <val> fflgs
%type <val> fflgs fflag
%type <str> rule
%type <attr> attr
%type <devb> devbase
@ -134,81 +135,73 @@ static void setmaxpartitions __P((int));
* definition files (via the include() mechanism), followed by the
* configuration specification(s) proper. In effect, this is two
* separate grammars, with some shared terminals and nonterminals.
* Note that we do not have sufficient keywords to enforce any order
* between elements of "topthings" without introducing shift/reduce
* conflicts. Instead, check order requirements in the C code.
*/
Configuration:
dirs hdrs machine_spec /* "machine foo" from machine descr. */
topthings /* dirspecs, include "std.arch" */
machine_spec /* "machine foo" from machine descr. */
dev_defs dev_eof /* sys/conf/files */
dev_defs dev_eof /* sys/arch/${MACHINE_ARCH}/... */
maxpart_spec dev_defs dev_eof /* sys/arch/${MACHINE}/... */
dev_defs dev_eof /* sys/arch/${MACHINE}/... */
{ check_maxpart(); }
specs; /* rest of machine description */
dirs:
dirspecs = { setupdirs(); };
dirspecs:
dirspecs dir |
topthings:
topthings topthing |
/* empty */;
dir:
SOURCE PATHNAME = { if (!srcdir) srcdir = $2; } |
BUILD PATHNAME = { if (!builddir) builddir = $2; } |
'\n';
hdrs:
hdrs hdr |
/* empty */;
hdr:
include |
topthing:
SOURCE PATHNAME '\n' { if (!srcdir) srcdir = $2; } |
BUILD PATHNAME '\n' { if (!builddir) builddir = $2; } |
include '\n' |
'\n';
machine_spec:
XMACHINE WORD = { setmachine($2,NULL); } |
XMACHINE WORD WORD = { setmachine($2,$3); } |
error = { stop("cannot proceed without machine specifier"); };
XMACHINE WORD '\n' { setmachine($2,NULL); } |
XMACHINE WORD WORD '\n' { setmachine($2,$3); } |
error { stop("cannot proceed without machine specifier"); };
dev_eof:
ENDFILE = { enddefs(lastfile); checkfiles(); };
maxpart_blanks:
maxpart_blanks '\n' |
/* empty */;
maxpart_spec:
maxpart_blanks MAXPARTITIONS NUMBER = { setmaxpartitions($3); } |
error = { stop("cannot proceed without maxpartitions specifier"); };
ENDFILE { enddefs(); checkfiles(); };
/*
* Various nonterminals shared between the grammars.
*/
file:
XFILE PATHNAME fopts fflgs rule = { addfile($2, $3, $4, $5); };
XFILE PATHNAME fopts fflgs rule { addfile($2, $3, $4, $5); };
/* order of options is important, must use right recursion */
fopts:
fexpr = { $$ = $1; } |
/* empty */ = { $$ = NULL; };
fexpr { $$ = $1; } |
/* empty */ { $$ = NULL; };
fexpr:
fatom = { $$ = $1; } |
'!' fatom = { $$ = fx_not($2); } |
fexpr '&' fexpr = { $$ = fx_and($1, $3); } |
fexpr '|' fexpr = { $$ = fx_or($1, $3); } |
'(' fexpr ')' = { $$ = $2; };
fatom { $$ = $1; } |
'!' fatom { $$ = fx_not($2); } |
fexpr '&' fexpr { $$ = fx_and($1, $3); } |
fexpr '|' fexpr { $$ = fx_or($1, $3); } |
'(' fexpr ')' { $$ = $2; };
fatom:
WORD = { $$ = fx_atom($1); };
WORD { $$ = fx_atom($1); };
fflgs:
fflgs FFLAG = { $$ = $1 | $2; } |
/* empty */ = { $$ = 0; };
fflgs fflag { $$ = $1 | $2; } |
/* empty */ { $$ = 0; };
fflag:
NEEDS_COUNT { $$ = FI_NEEDSCOUNT; } |
NEEDS_FLAG { $$ = FI_NEEDSFLAG; };
rule:
COMPILE_WITH WORD = { $$ = $2; } |
/* empty */ = { $$ = NULL; };
COMPILE_WITH WORD { $$ = $2; } |
/* empty */ { $$ = NULL; };
include:
INCLUDE WORD = { include($2, '\n'); };
INCLUDE WORD { include($2, 0); };
/*
* The machine definitions grammar.
@ -218,87 +211,87 @@ dev_defs:
/* empty */;
dev_def:
one_def '\n' = { adepth = 0; } |
one_def '\n' { adepth = 0; } |
'\n' |
error '\n' = { cleanup(); };
error '\n' { cleanup(); };
one_def:
file |
include |
DEFINE WORD interface_opt = { (void)defattr($2, $3); } |
DEFINE WORD interface_opt { (void)defattr($2, $3); } |
DEVICE devbase interface_opt attrs_opt
= { defdev($2, 0, $3, $4); } |
{ defdev($2, 0, $3, $4); } |
ATTACH devbase AT atlist devattach_opt attrs_opt
= { defdevattach($5, $2, $4, $6); } |
MAXUSERS NUMBER NUMBER NUMBER = { setdefmaxusers($2, $3, $4); } |
PSEUDO_DEVICE devbase attrs_opt = { defdev($2,1,NULL,$3); } |
{ defdevattach($5, $2, $4, $6); } |
MAXPARTITIONS NUMBER { maxpartitions = $2; } |
MAXUSERS NUMBER NUMBER NUMBER { setdefmaxusers($2, $3, $4); } |
PSEUDO_DEVICE devbase attrs_opt { defdev($2,1,NULL,$3); } |
MAJOR '{' majorlist '}';
atlist:
atlist ',' atname = { $$ = new_nx($3, $1); } |
atname = { $$ = new_n($1); };
atlist ',' atname { $$ = new_nx($3, $1); } |
atname { $$ = new_n($1); };
atname:
WORD = { $$ = $1; } |
ROOT = { $$ = NULL; };
WORD { $$ = $1; } |
ROOT { $$ = NULL; };
devbase:
WORD = { $$ = getdevbase($1); };
WORD { $$ = getdevbase($1); };
devattach_opt:
WITH WORD = { $$ = getdevattach($2); } |
/* empty */ = { $$ = NULL; };
WITH WORD { $$ = getdevattach($2); } |
/* empty */ { $$ = NULL; };
interface_opt:
'{' loclist_opt '}' = { $$ = new_nx("", $2); } |
/* empty */ = { $$ = NULL; };
'{' loclist_opt '}' { $$ = new_nx("", $2); } |
/* empty */ { $$ = NULL; };
loclist_opt:
loclist = { $$ = $1; } |
/* empty */ = { $$ = NULL; };
loclist { $$ = $1; } |
/* empty */ { $$ = NULL; };
/* loclist order matters, must use right recursion */
loclist:
locdef ',' loclist = { ($$ = $1)->nv_next = $3; } |
locdef = { $$ = $1; };
locdef ',' loclist { ($$ = $1)->nv_next = $3; } |
locdef { $$ = $1; };
/* "[ WORD locdefault ]" syntax may be unnecessary... */
locdef:
WORD locdefault = { $$ = new_nsi($1, $2, 0); } |
WORD = { $$ = new_nsi($1, NULL, 0); } |
'[' WORD locdefault ']' = { $$ = new_nsi($2, $3, 1); };
WORD locdefault { $$ = new_nsi($1, $2, 0); } |
WORD { $$ = new_nsi($1, NULL, 0); } |
'[' WORD locdefault ']' { $$ = new_nsi($2, $3, 1); };
locdefault:
'=' value = { $$ = $2; };
'=' value { $$ = $2; };
value:
WORD = { $$ = $1; } |
signed_number = { char bf[40];
WORD { $$ = $1; } |
signed_number { char bf[40];
(void)sprintf(bf, FORMAT($1), $1);
$$ = intern(bf); };
signed_number:
NUMBER = { $$ = $1; } |
'-' NUMBER = { $$ = -$2; };
NUMBER { $$ = $1; } |
'-' NUMBER { $$ = -$2; };
attrs_opt:
':' attrs = { $$ = $2; } |
/* empty */ = { $$ = NULL; };
':' attrs { $$ = $2; } |
/* empty */ { $$ = NULL; };
attrs:
attrs ',' attr = { $$ = new_px($3, $1); } |
attr = { $$ = new_p($1); };
attrs ',' attr { $$ = new_px($3, $1); } |
attr { $$ = new_p($1); };
attr:
WORD = { $$ = getattr($1); };
WORD { $$ = getattr($1); };
majorlist:
majorlist ',' majordef |
majordef;
majordef:
devbase '=' NUMBER = { setmajor($1, $3); };
devbase '=' NUMBER { setmajor($1, $3); };
/*
@ -309,38 +302,38 @@ specs:
/* empty */;
spec:
config_spec '\n' = { adepth = 0; } |
config_spec '\n' { adepth = 0; } |
'\n' |
error '\n' = { cleanup(); };
error '\n' { cleanup(); };
config_spec:
file |
include |
OPTIONS opt_list |
MAKEOPTIONS mkopt_list |
MAXUSERS NUMBER = { setmaxusers($2); } |
CONFIG conf sysparam_list = { addconf(&conf); } |
PSEUDO_DEVICE WORD npseudo = { addpseudo($2, $3); } |
MAXUSERS NUMBER { setmaxusers($2); } |
CONFIG conf sysparam_list { addconf(&conf); } |
PSEUDO_DEVICE WORD npseudo { addpseudo($2, $3); } |
device_instance AT attachment locators flags_opt
= { adddev($1, $3, $4, $5); };
{ adddev($1, $3, $4, $5); };
mkopt_list:
mkopt_list ',' mkoption |
mkoption;
mkoption:
WORD '=' value = { addmkoption($1, $3); }
WORD '=' value { addmkoption($1, $3); }
opt_list:
opt_list ',' option |
option;
option:
WORD = { addoption($1, NULL); } |
WORD '=' value = { addoption($1, $3); };
WORD { addoption($1, NULL); } |
WORD '=' value { addoption($1, $3); };
conf:
WORD = { conf.cf_name = $1;
WORD { conf.cf_name = $1;
conf.cf_lineno = currentline();
conf.cf_root = NULL;
conf.cf_swap = NULL;
@ -351,48 +344,48 @@ sysparam_list:
sysparam;
sysparam:
ROOT on_opt dev_spec = { setconf(&conf.cf_root, "root", $3); } |
SWAP on_opt swapdev_list = { setconf(&conf.cf_swap, "swap", $3); } |
DUMPS on_opt dev_spec = { setconf(&conf.cf_dump, "dumps", $3); };
ROOT on_opt dev_spec { setconf(&conf.cf_root, "root", $3); } |
SWAP on_opt swapdev_list { setconf(&conf.cf_swap, "swap", $3); } |
DUMPS on_opt dev_spec { setconf(&conf.cf_dump, "dumps", $3); };
swapdev_list:
dev_spec AND swapdev_list = { ($$ = $1)->nv_next = $3; } |
dev_spec = { $$ = $1; };
dev_spec AND swapdev_list { ($$ = $1)->nv_next = $3; } |
dev_spec { $$ = $1; };
dev_spec:
WORD = { $$ = new_si($1, NODEV); } |
major_minor = { $$ = new_si(NULL, $1); };
WORD { $$ = new_si($1, NODEV); } |
major_minor { $$ = new_si(NULL, $1); };
major_minor:
MAJOR NUMBER MINOR NUMBER = { $$ = makedev($2, $4); };
MAJOR NUMBER MINOR NUMBER { $$ = makedev($2, $4); };
on_opt:
ON | /* empty */;
npseudo:
NUMBER = { $$ = $1; } |
/* empty */ = { $$ = 1; };
NUMBER { $$ = $1; } |
/* empty */ { $$ = 1; };
device_instance:
WORD '*' = { $$ = starref($1); } |
WORD = { $$ = $1; };
WORD '*' { $$ = starref($1); } |
WORD { $$ = $1; };
attachment:
ROOT = { $$ = NULL; } |
WORD '?' = { $$ = wildref($1); } |
WORD = { $$ = $1; };
ROOT { $$ = NULL; } |
WORD '?' { $$ = wildref($1); } |
WORD { $$ = $1; };
locators:
locators locator = { ($$ = $2)->nv_next = $1; } |
/* empty */ = { $$ = NULL; };
locators locator { ($$ = $2)->nv_next = $1; } |
/* empty */ { $$ = NULL; };
locator:
WORD value = { $$ = new_ns($1, $2); } |
WORD '?' = { $$ = new_ns($1, NULL); };
WORD value { $$ = new_ns($1, $2); } |
WORD '?' { $$ = new_ns($1, NULL); };
flags_opt:
FLAGS NUMBER = { $$ = $2; } |
/* empty */ = { $$ = 0; };
FLAGS NUMBER { $$ = $2; } |
/* empty */ { $$ = 0; };
%%
@ -404,48 +397,6 @@ yyerror(s)
error("%s", s);
}
/*
* Verify/create builddir if necessary, change to it, and verify srcdir.
*/
static void
setupdirs()
{
struct stat st;
char *prof;
/* srcdir must be specified if builddir is not specified or if
* no configuration filename was specified. */
if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir)
stop("source directory must be specified");
if (srcdir == NULL)
srcdir = "../../../..";
if (builddir == NULL)
builddir = defbuilddir;
if (stat(builddir, &st) != 0) {
if (mkdir(builddir, 0777)) {
(void)fprintf(stderr, "config: cannot create %s: %s\n",
builddir, strerror(errno));
exit(2);
}
} else if (!S_ISDIR(st.st_mode)) {
(void)fprintf(stderr, "config: %s is not a directory\n",
builddir);
exit(2);
}
if (chdir(builddir) != 0) {
(void)fprintf(stderr, "config: cannot change to %s\n",
builddir);
exit(2);
}
if (stat(srcdir, &st) != 0 || !S_ISDIR(st.st_mode)) {
(void)fprintf(stderr, "config: %s is not a directory\n",
srcdir);
exit(2);
}
}
/*
* Cleanup procedure after syntax error: release any nvlists
* allocated during parsing the current line.
@ -488,9 +439,9 @@ setmachine(mch, mcharch)
}
static void
setmaxpartitions(n)
int n;
check_maxpart()
{
maxpartitions = n;
if (maxpartitions <= 0) {
stop("cannot proceed without maxpartitions specifier");
}
}

View File

@ -1,5 +1,5 @@
%{
/* $NetBSD: scan.l,v 1.8 1996/11/07 22:59:44 gwr Exp $ */
/* $NetBSD: scan.l,v 1.9 1996/11/11 23:54:18 gwr Exp $ */
/*
* Copyright (c) 1992, 1993
@ -66,17 +66,16 @@ struct incl {
YY_BUFFER_STATE in_buf; /* previous lex state */
const char *in_fname; /* previous file name */
int in_lineno; /* previous line number */
int in_preveof; /* previous eoftoken */
int in_ateof; /* token to insert at EOF */
};
static struct incl *incl;
static int eoftoken; /* current EOF token */
static void endinclude __P((void));
static int endinclude __P((void));
#define yywrap() 1
%}
PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]*
PATH [A-Za-z_0-9]*[./][-A-Za-z_0-9./]*
WORD [A-Za-z_][-A-Za-z_0-9]*
%%
@ -91,27 +90,25 @@ config { return CONFIG; }
define { return DEFINE; }
device { return DEVICE; }
dumps { return DUMPS; }
flags { return FLAGS; }
file { return XFILE; }
flags { return FLAGS; }
include { return INCLUDE; }
machine { return XMACHINE; }
major { return MAJOR; }
makeoptions { return MAKEOPTIONS; }
maxusers { return MAXUSERS; }
maxpartitions { return MAXPARTITIONS; }
maxusers { return MAXUSERS; }
minor { return MINOR; }
needs-count { return NEEDS_COUNT; }
needs-flag { return NEEDS_FLAG; }
on { return ON; }
options { return OPTIONS; }
"pseudo-device" { return PSEUDO_DEVICE; }
pseudo-device { return PSEUDO_DEVICE; }
root { return ROOT; }
source { return SOURCE; }
swap { return SWAP; }
with { return WITH; }
/* keywords with values */
needs-count { yylval.val = FI_NEEDSCOUNT; return FFLAG; }
needs-flag { yylval.val = FI_NEEDSFLAG; return FFLAG; }
/* all the rest */
{PATH} { yylval.str = intern(yytext); return PATHNAME; }
{WORD} { yylval.str = intern(yytext); return WORD; }
@ -133,9 +130,6 @@ needs-flag { yylval.val = FI_NEEDSFLAG; return FFLAG; }
yylval.val = strtol(yytext, NULL, 10);
return NUMBER;
}
\n/[ \t] {
yyline++;
}
\n {
yyline++;
return '\n';
@ -145,12 +139,12 @@ needs-flag { yylval.val = FI_NEEDSFLAG; return FFLAG; }
. { return yytext[0]; }
<<EOF>> {
int tok;
tok = eoftoken;
eoftoken = YY_NULL;
if (incl != NULL)
endinclude();
return (tok);
if (incl == NULL)
return YY_NULL;
tok = endinclude();
if (tok)
return tok;
/* otherwise continue scanning */
}
%%
@ -167,7 +161,6 @@ firstfile(fname)
return (-1);
yyfile = conffile = fname;
yyline = 1;
eoftoken = YY_NULL;
return (0);
}
@ -175,17 +168,23 @@ firstfile(fname)
* Open the named file for inclusion at the current point. Returns 0 on
* success (file opened and previous state pushed), nonzero on failure
* (fopen failed, complaint made). The `ateof' parameter controls the
* token to be returned at the end of the include file (typically '\n'
* or ENDFILE).
* token to be inserted at the end of the include file (i.e. ENDFILE).
* If ateof == 0 then nothing is inserted.
*/
int
include(fname, ateof)
const char *fname;
int ateof;
{
register FILE *fp;
register struct incl *in;
FILE *fp;
struct incl *in;
char *s;
static int havedirs;
if (havedirs == 0) {
havedirs = 1;
setupdirs();
}
/* Kludge until files.* files are fixed. */
if (strncmp(fname, "../../../", 9) == 0)
@ -202,12 +201,11 @@ include(fname, ateof)
in->in_buf = YY_CURRENT_BUFFER;
in->in_fname = yyfile;
in->in_lineno = yyline;
in->in_preveof = eoftoken;
in->in_ateof = ateof;
incl = in;
yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
yyfile = intern(s);
yyline = 1;
eoftoken = ateof;
free(s);
return (0);
}
@ -215,10 +213,11 @@ include(fname, ateof)
/*
* Terminate the most recent inclusion.
*/
static void
static int
endinclude()
{
register struct incl *in;
struct incl *in;
int ateof;
if ((in = incl) == NULL)
panic("endinclude");
@ -229,8 +228,10 @@ endinclude()
yy_switch_to_buffer(in->in_buf);
yyfile = in->in_fname;
yyline = in->in_lineno;
eoftoken = in->in_preveof;
ateof = in->in_ateof;
free(in);
return (ateof);
}
/*