The computation of nullable is broken: it doesn't handle empty

RHS's properly.
* tests/torture.at (GNU AWK Grammar): New.
* tests/sets.at (Nullable): New.
* src/nullable.c (set_nullable): Instead of blindly looping over
`ritems', loop over the rules, and then over their rhs's.
Work around Autotest bugs.
* src/warshall.c (bitmatrix_print): Don't use `+--+' as table
frame, because Autotest understand lines starting with a `+' as
traces from the shell.  Then, they are not processed properly.
Admittedly an Autotest bug, but we don't have time to wait for
Autotest to catch up.
* tests/regression.at (Broken Closure): Adjust to the new table
frames.
Move to...
* tests/sets.at: here.
This commit is contained in:
Akim Demaille
2001-12-13 11:02:21 +00:00
parent cb581495e6
commit ed8e1f68e9
8 changed files with 600 additions and 124 deletions

View File

@@ -114,3 +114,343 @@ AT_CHECK([input 900], 0, [], [ignore])
AT_CHECK([input 10000], 1, [], [ignore])
AT_CLEANUP
## ----------------- ##
## GNU AWK Grammar. ##
## ----------------- ##
AT_SETUP([GNU AWK Grammar])
# We have been careful to strip all the actions excepts the
# mid-rule actions. We rely on %expect to check that there are
# indeed 65 SR conflicts.
#
# Bison was once wrong, due to an incorrect computation of nullable.
# It reported 485 SR conflicts!
AT_DATA([[input.y]],
[[%expect 65
%token FUNC_CALL NAME REGEXP
%token ERROR
%token YNUMBER YSTRING
%token RELOP APPEND_OP
%token ASSIGNOP MATCHOP NEWLINE CONCAT_OP
%token LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE
%token LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE
%token LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION
%token LEX_GETLINE LEX_NEXTFILE
%token LEX_IN
%token LEX_AND LEX_OR INCREMENT DECREMENT
%token LEX_BUILTIN LEX_LENGTH
/* Lowest to highest */
%right ASSIGNOP
%right '?' ':'
%left LEX_OR
%left LEX_AND
%left LEX_GETLINE
%nonassoc LEX_IN
%left FUNC_CALL LEX_BUILTIN LEX_LENGTH
%nonassoc ','
%nonassoc MATCHOP
%nonassoc RELOP '<' '>' '|' APPEND_OP TWOWAYIO
%left CONCAT_OP
%left YSTRING YNUMBER
%left '+' '-'
%left '*' '/' '%'
%right '!' UNARY
%right '^'
%left INCREMENT DECREMENT
%left '$'
%left '(' ')'
%%
start
: opt_nls program opt_nls
;
program
: rule
| program rule
| error
| program error
| /* empty */
;
rule
: LEX_BEGIN {} action
| LEX_END {} action
| LEX_BEGIN statement_term
| LEX_END statement_term
| pattern action
| action
| pattern statement_term
| function_prologue function_body
;
func_name
: NAME
| FUNC_CALL
| lex_builtin
;
lex_builtin
: LEX_BUILTIN
| LEX_LENGTH
;
function_prologue
: LEX_FUNCTION {} func_name '(' opt_param_list r_paren opt_nls
;
function_body
: l_brace statements r_brace opt_semi opt_nls
| l_brace r_brace opt_semi opt_nls
;
pattern
: exp
| exp ',' exp
;
regexp
/*
* In this rule, want_regexp tells yylex that the next thing
* is a regexp so it should read up to the closing slash.
*/
: '/' {} REGEXP '/'
;
action
: l_brace statements r_brace opt_semi opt_nls
| l_brace r_brace opt_semi opt_nls
;
statements
: statement
| statements statement
| error
| statements error
;
statement_term
: nls
| semi opt_nls
;
statement
: semi opt_nls
| l_brace r_brace
| l_brace statements r_brace
| if_statement
| LEX_WHILE '(' exp r_paren opt_nls statement
| LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls
| LEX_FOR '(' NAME LEX_IN NAME r_paren opt_nls statement
| LEX_FOR '(' opt_exp semi opt_nls exp semi opt_nls opt_exp r_paren opt_nls statement
| LEX_FOR '(' opt_exp semi opt_nls semi opt_nls opt_exp r_paren opt_nls statement
| LEX_BREAK statement_term
| LEX_CONTINUE statement_term
| print '(' expression_list r_paren output_redir statement_term
| print opt_rexpression_list output_redir statement_term
| LEX_NEXT statement_term
| LEX_NEXTFILE statement_term
| LEX_EXIT opt_exp statement_term
| LEX_RETURN {} opt_exp statement_term
| LEX_DELETE NAME '[' expression_list ']' statement_term
| LEX_DELETE NAME statement_term
| exp statement_term
;
print
: LEX_PRINT
| LEX_PRINTF
;
if_statement
: LEX_IF '(' exp r_paren opt_nls statement
| LEX_IF '(' exp r_paren opt_nls statement
LEX_ELSE opt_nls statement
;
nls
: NEWLINE
| nls NEWLINE
;
opt_nls
: /* empty */
| nls
;
input_redir
: /* empty */
| '<' simp_exp
;
output_redir
: /* empty */
| '>' exp
| APPEND_OP exp
| '|' exp
| TWOWAYIO exp
;
opt_param_list
: /* empty */
| param_list
;
param_list
: NAME
| param_list comma NAME
| error
| param_list error
| param_list comma error
;
/* optional expression, as in for loop */
opt_exp
: /* empty */
| exp
;
opt_rexpression_list
: /* empty */
| rexpression_list
;
rexpression_list
: rexp
| rexpression_list comma rexp
| error
| rexpression_list error
| rexpression_list error rexp
| rexpression_list comma error
;
opt_expression_list
: /* empty */
| expression_list
;
expression_list
: exp
| expression_list comma exp
| error
| expression_list error
| expression_list error exp
| expression_list comma error
;
/* Expressions, not including the comma operator. */
exp : variable ASSIGNOP {} exp
| '(' expression_list r_paren LEX_IN NAME
| exp '|' LEX_GETLINE opt_variable
| exp TWOWAYIO LEX_GETLINE opt_variable
| LEX_GETLINE opt_variable input_redir
| exp LEX_AND exp
| exp LEX_OR exp
| exp MATCHOP exp
| regexp
| '!' regexp %prec UNARY
| exp LEX_IN NAME
| exp RELOP exp
| exp '<' exp
| exp '>' exp
| exp '?' exp ':' exp
| simp_exp
| exp simp_exp %prec CONCAT_OP
;
rexp
: variable ASSIGNOP {} rexp
| rexp LEX_AND rexp
| rexp LEX_OR rexp
| LEX_GETLINE opt_variable input_redir
| regexp
| '!' regexp %prec UNARY
| rexp MATCHOP rexp
| rexp LEX_IN NAME
| rexp RELOP rexp
| rexp '?' rexp ':' rexp
| simp_exp
| rexp simp_exp %prec CONCAT_OP
;
simp_exp
: non_post_simp_exp
/* Binary operators in order of decreasing precedence. */
| simp_exp '^' simp_exp
| simp_exp '*' simp_exp
| simp_exp '/' simp_exp
| simp_exp '%' simp_exp
| simp_exp '+' simp_exp
| simp_exp '-' simp_exp
| variable INCREMENT
| variable DECREMENT
;
non_post_simp_exp
: '!' simp_exp %prec UNARY
| '(' exp r_paren
| LEX_BUILTIN
'(' opt_expression_list r_paren
| LEX_LENGTH '(' opt_expression_list r_paren
| LEX_LENGTH
| FUNC_CALL '(' opt_expression_list r_paren
| variable
| INCREMENT variable
| DECREMENT variable
| YNUMBER
| YSTRING
| '-' simp_exp %prec UNARY
| '+' simp_exp %prec UNARY
;
opt_variable
: /* empty */
| variable
;
variable
: NAME
| NAME '[' expression_list ']'
| '$' non_post_simp_exp
;
l_brace
: '{' opt_nls
;
r_brace
: '}' opt_nls
;
r_paren
: ')'
;
opt_semi
: /* empty */
| semi
;
semi
: ';'
;
comma : ',' opt_nls
;
%%
]])
# Pass plenty of options, to exercise plenty of code, even if we
# don't actually check the output. But SEGV is watching us, and
# so might do dmalloc.
AT_CHECK([[bison --verbose --defines input.y]])
AT_CLEANUP