I've been following the youtube video https://www.youtube.com/watch?v=fFRxWtRibC8
I've created the lexer.l file with the following:
%{
/* definitions */
#include "parser.tab.h"
%}
/* rules */
%%
[0-9]+ {yylval.num = atoi(yytext); return NUMBER; }
\n {return EOL;}
. {}
%%
yywrap() {}
int main() {
yylex();
return 0;
}
and the parser.y file with the following:
%{
/* definitions */
%}
%union{
int num;
char sym;
}
%token EOL
%token<num> NUMBER
%type<num> exp
%token PLUS
/* rules */
%%
input:
exp EOL {printf("%d\n", $1); }
| EOL;
exp:
NUMBER { $$ = $1; }
| exp PLUS exp { $$ = $1 + $3; }
;
%%
int main() {
yyparse();
return 0;
}
void yyerror (char* s) {
printf ("ERROR: %s\n", s);
return 0;
}
When running the command "gcc lex.yy.c parser.tab.c", I'm getting the following error:
undefined reference to `yyerror'
collect2.exe: error: ld returned 1 exit status
Related
So I am having this .y file on which I am trying to parse and evaluate a function with it's parameters, but a have one shift/reduce conflict that I cannot identify:
.y
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "types.h"
#define YYDEBUG 0
/* prototypes */
nodeType *opr(int oper, int nops, ...);
nodeType *id(int i);
nodeType *con(int value);
void freeNode(nodeType *p);
void yyerror(char *s);
nodeType *RadEc;
int sym[26]; /* symbol table */
%}
%union {
int iValue; /* integer value */
char sIndex; /* symbol table index */
nodeType *nPtr; /* node pointer */
};
%token <iValue> INTEGER
%token <sIndex> VARIABLE
%token WHILE IF PRINT SUBRAD ENDSUB THEN DO ENDIF RAD
%nonassoc IFX
%nonassoc ELSE
%left GE LE EQ NE '>' '<'
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%type <nPtr> statement expr stmt_list
%type <iValue> expresie
%start program
%%
program : declaratii cod { exit(0); }
;
declaratii: SUBRAD stmt_list ENDSUB { RadEc=$2; }
| /* NULL */
;
statement : '\n' { $$ = opr(';', 2, NULL, NULL); }
| expr '\n' { $$ = $1; }
| PRINT expr '\n' { $$ = opr(PRINT, 1, $2); }
| VARIABLE '=' expr '\n' { $$ = opr('=', 2, id($1), $3); }
| DO stmt_list WHILE expr { $$ = opr(WHILE, 2, $4, $2); }
| IF expr THEN stmt_list ENDIF %prec IFX { $$ = opr(IF, 2, $2, $4); }
| IF expr THEN stmt_list ELSE stmt_list ENDIF { $$ = opr(IF, 3, $2, $4, $6); }
;
stmt_list : statement
| stmt_list statement { $$ = opr(';', 2, $1, $2); }
;
expr : INTEGER { $$ = con($1); }
| VARIABLE { $$ = id($1); }
| '-' expr %prec UMINUS { $$ = opr(UMINUS, 1, $2); }
| expr '+' expr { $$ = opr('+', 2, $1, $3); }
| expr '-' expr { $$ = opr('-', 2, $1, $3); }
| expr '*' expr { $$ = opr('*', 2, $1, $3); }
| expr '/' expr { $$ = opr('/', 2, $1, $3); }
| expr '<' expr { $$ = opr('<', 2, $1, $3); }
| expr '>' expr { $$ = opr('>', 2, $1, $3); }
| expr GE expr { $$ = opr(GE, 2, $1, $3); }
| expr LE expr { $$ = opr(LE, 2, $1, $3); }
| expr NE expr { $$ = opr(NE, 2, $1, $3); }
| expr EQ expr { $$ = opr(EQ, 2, $1, $3); }
| '(' expr ')' { $$ = $2; }
;
cod : '.' {exit(0);}
| instruc '\n' cod
;
instruc : '\n'
| PRINT expresie {printf("%d\n",$2);}
| VARIABLE '=' expresie {sym[$1]=$3;}
| RAD'('expresie','expresie','expresie')' {sym[0]=$3; sym[1]=$5; sym[2]=$7; ex(RadEc);}
;
expresie : INTEGER { $$ = $1; }
| VARIABLE { $$ = sym[$1]; }
| '-' expresie %prec UMINUS { $$ = -$2; }
| expresie '+' expresie { $$ = $1+$3; }
| expresie '-' expresie { $$ = $1-$3; }
| expresie '*' expresie { $$ = $1*$3; }
| expresie '/' expresie { $$ = $1/$3; }
| expresie '<' expresie { $$ = $1<$3; }
| expresie '>' expresie { $$ = $1>$3; }
| expresie GE expresie { $$ = $1>=$3; }
| expresie LE expresie { $$ = $1<=$3; }
| expresie NE expresie { $$ = $1!=$3; }
| expresie EQ expresie { $$ = $1==$3; }
| '(' expresie ')' { $$ = $2; }
;
%%
nodeType *con(int value)
{
nodeType *p;
/* allocate node */
if ((p = malloc(sizeof(conNodeType))) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeCon;
p->con.value = value;
return p;
}
nodeType *id(int i)
{
nodeType *p;
/* allocate node */
if ((p = malloc(sizeof(idNodeType))) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeId;
p->id.i = i;
return p;
}
nodeType *opr(int oper, int nops, ...)
{
va_list ap;
nodeType *p;
size_t size;
int i;
/* allocate node */
size = sizeof(oprNodeType) + (nops - 1) * sizeof(nodeType*);
if ((p = malloc(size)) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeOpr;
p->opr.oper = oper;
p->opr.nops = nops;
va_start(ap, nops);
for (i = 0; i < nops; i++)
p->opr.op[i] = va_arg(ap, nodeType*);
va_end(ap);
return p;
}
void freeNode(nodeType *p)
{
int i;
if (!p)
return;
if (p->type == typeOpr) {
for (i = 0; i < p->opr.nops; i++)
freeNode(p->opr.op[i]);
}
free (p);
}
int ex(nodeType *p)
{
if (!p)
return 0;
switch(p->type)
{
case typeCon: return p->con.value;
case typeId: return sym[p->id.i];
case typeOpr: switch(p->opr.oper)
{
case WHILE: while(ex(p->opr.op[0]))
ex(p->opr.op[1]);
return 0;
case IF: if (ex(p->opr.op[0]))
ex(p->opr.op[1]);
else if (p->opr.nops > 2)
ex(p->opr.op[2]);
return 0;
case PRINT: printf("%d\n", ex(p->opr.op[0]));
return 0;
case ';': ex(p->opr.op[0]);
return ex(p->opr.op[1]);
case '=': return sym[p->opr.op[0]->id.i] = ex(p->opr.op[1]);
case UMINUS: return -ex(p->opr.op[0]);
case '+': return ex(p->opr.op[0]) + ex(p->opr.op[1]);
case '-': return ex(p->opr.op[0]) - ex(p->opr.op[1]);
case '*': return ex(p->opr.op[0]) * ex(p->opr.op[1]);
case '/': return ex(p->opr.op[0]) / ex(p->opr.op[1]);
case '<': return ex(p->opr.op[0]) < ex(p->opr.op[1]);
case '>': return ex(p->opr.op[0]) > ex(p->opr.op[1]);
case GE: return ex(p->opr.op[0]) >= ex(p->opr.op[1]);
case LE: return ex(p->opr.op[0]) <= ex(p->opr.op[1]);
case NE: return ex(p->opr.op[0]) != ex(p->opr.op[1]);
case EQ: return ex(p->opr.op[0]) == ex(p->opr.op[1]);
}
}
}
void yyerror(char *s)
{
fprintf(stdout, "%s\n", s);
}
int main(void)
{
#if YYDEBUG
yydebug = 1;
#endif
yyparse();
return 0;
}
I tried different ways to see were am I losing something, but I am pretty new at this and still cannot figure it out very well the conflicts.
Any help much appreciated.
Your grammar allows statements to be expressions and it allows two statements to appear in sequence without any separator.
Now, both of the following are expressions:
a
-1
Suppose they appear like that in a statement list. How is that different from this single expression?
a - 1
Ambiguity always shows up as a parsing conflict.
By the way, delimited if statements (with an endif marker) cannot exhibit the dangling else ambiguity. The endif bracket makes the parse unambiguous. So all of the precedence apparatus copied from a different grammar is totally redundant here.
I am trying to run my first flex bison project and this happens:
aky#aky-VirtualBox:~/wk1$ flex project1.l
aky#aky-VirtualBox:~/wk1$ bison -d project1.y
aky#aky-VirtualBox:~/wk1$ gcc -o project1 project1.c project1.tab.c lex.yy.c
project1.c: In function ‘main’:
project1.c:18:9: warning: implicit declaration of function ‘yyparse’
project1.tab.c:1213:16: warning: implicit declaration of function ‘yylex’
lex.yy.c:(.text+0x470): undefined reference to `lookup'
The related code:
project1.c ----------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "project1.h"
void yyerror(char *s)
{
fprintf(stderr, "error: %s\n", s);
}
int main(int argc, char **argv)
{
extern FILE *yyin;
++argv; --argc;
yyin = fopen(argv[0], "r");
return yyparse();
}
project1.l ------------------------
%option noyywrap nodefault yylineno
%{
#include "project1.h"
#include "project1.tab.h"
%}
EXP ([Ex][-+]?[0-9]+)
%%
".." { return DOTS; }
"+" |
"-" |
"*" |
"/" |
"=" |
"|" |
"," |
";" |
":" |
"." |
"[" |
"]" |
"{" |
"}" |
"(" |
")" { return yytext[0]; }
">" { yylval.fn = 1; return CMP; }
"<" { yylval.fn = 2; return CMP; }
"<>" { yylval.fn = 3; return CMP; }
"==" { yylval.fn = 4; return CMP; }
">=" { yylval.fn = 5; return CMP; }
"<=" { yylval.fn = 6; return CMP; }
"integer" { yylval.type_c = 'a'; return STD_TYPE; }
"real" { yylval.type_c = 'b'; return STD_TYPE; }
"program" { return PROGRAM; }
"var" { return VAR; }
"array" { return ARRAY; }
"of" { return OF; }
"begin" { return BGN; }
"end" { return END; }
"if" { return IF; }
"then" { return THEN; }
"else" { return ELSE; }
"while" {return WHILE; }
"do" { return DO; }
"print" { return PRINT; }
[a-zA-Z][a-zA-Z0-9]* { yylval.s = lookup(yytext); return ID; }
[0-9]+"."[0-9]+ |
[0-9]+ { yylval.d = atof(yytext); return NUMBER; }
"//".*
[ \t\n]
. { yyerror("Mystery character.\n"); }
%%
project1.y ------------------------
%{
#include <stdio.h>
#include <stdlib.h>
#include "project1.h"
%}
%union {
struct ast *a;
double d;
struct symbol *s;
struct symlist *sl;
struct numlist *nl;
int fn;
char type_c;
}
/* declare tokens */
%token <d> NUMBER
%token <s> ID
%token PROGRAM VAR ARRAY OF INTEGER REAL BGN END IF THEN ELSE WHILE DO DOTS PRINT
%token <type_c> STD_TYPE
%nonassoc <fn> CMP
%right '='
%left '+' '-'
%left '*' '/'
%nonassoc '|' UMINUS
%type <a> decl_list decl stmt_list stmt exp
%type <sl> id_list
%type <nl> num_list
%start program
%%
program: PROGRAM ID '(' id_list ')' ';' decl_list BGN stmt_list END '.'
{ printf("new program.\n"); }
;
decl_list: { /*$$ = NULL;*/ }
| decl ';' decl_list { printf("new declaration.\n"); }
;
decl: VAR id_list ':' STD_TYPE { }
| VAR id_list ':' ARRAY '[' NUMBER DOTS NUMBER ']' OF STD_TYPE
{ }
;
stmt: IF exp THEN '{' stmt_list '}' { }
| IF exp THEN '{' stmt_list '}' ELSE '{' stmt_list '}' { }
| WHILE exp DO '{' stmt_list '}' { }
| exp
;
stmt_list: stmt { printf("new statement.\n"); }
| stmt_list ';' stmt { }
;
exp: exp CMP exp { }
| exp '+' exp { }
| exp '-' exp { }
| exp '*' exp { }
| exp '/' exp { }
| '|' exp { }
| '(' exp ')' { }
| '-' exp %prec UMINUS { }
| NUMBER{ }
| ID { }
| ID '[' exp ']' { }
| ID '[' exp ']' '=' exp { }
| ID '=' exp { }
| ID '=' '{' num_list '}' { }
| PRINT '(' exp ')' { }
;
num_list: NUMBER { }
| NUMBER ',' num_list {}
;
id_list: ID { }
| ID ',' id_list { }
;
%%
project1.tab.h --------------------
#ifndef YY_YY_PROJECT1_TAB_H_INCLUDED
# define YY_YY_PROJECT1_TAB_H_INCLUDED
/* Debug traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int yydebug;
#endif
/* Token type. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
enum yytokentype
{
NUMBER = 258,
ID = 259,
PROGRAM = 260,
VAR = 261,
ARRAY = 262,
OF = 263,
INTEGER = 264,
REAL = 265,
BGN = 266,
END = 267,
IF = 268,
THEN = 269,
ELSE = 270,
WHILE = 271,
DO = 272,
DOTS = 273,
PRINT = 274,
STD_TYPE = 275,
CMP = 276,
UMINUS = 277
};
#endif
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
#line 7 "project1.y" /* yacc.c:1909 */
struct ast *a;
double d;
struct symbol *s;
struct symlist *sl;
struct numlist *nl;
int fn;
char type_c;
#line 87 "project1.tab.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
extern YYSTYPE yylval;
int yyparse (void);
#endif /* !YY_YY_PROJECT1_TAB_H_INCLUDED */
yyparse is declared in project1.tab.h so you need to #include that file in any translation unit which refers to yyparse.
yylex is not declared in any header. In your yacc/bison file, you need to insert a correct declaration:
int yylex(void);
That should go after the #includes.
It's not clear to me which file lookup is defined in, but you need to add it to your final compilation command .
I have been using flex and bison for making a small calculator. My files are the following:
bisonFile.y
%{
#include <stdio.h>
%}
/* declare tokens */
%token NUMBER
%token ADD SUB MUL DIV ABS
%token EOL
%%
calclist: /* nothing */
| calclist exp EOL { printf("= %d\n", $2); }
;
exp: factor
| exp ADD factor { $$ = $1 + $3; }
| exp SUB factor { $$ = $1 - $3; }
;
factor: term
| factor MUL term { $$ = $1 * $3; }
| factor DIV term { $$ = $1 / $3; }
;
term: NUMBER
| ABS term { $$ = $2 >= 0? $2 : - $2; }
;
%%
main(int argc, char **argv)
{
yyparse();
}
yyerror(char *s)
{
fprintf(stderr, "error: %s\n", s);
}
flexFile.l
%{
# include "f5.tab.h"
int yylval;
%}
/* reconocimiento de tokens e impresion */
%{
int yylval;
%}
%option noyywrap
%%
"+" { return ADD; }
"-" { return SUB; }
"*" { return MUL; }
"/" { return DIV; }
"|" { return ABS; }
[0-9]+("."[0-9]+)? { yylval = atoi(yytext); return NUMBER; } //part added
\n { return EOL; }
[ \t] { /* ignore whitespace */ }
. { printf("Mystery character %c\n", *yytext); }
%%
My program works fine with integer numbers, and it also recognizes real numbers, but the problem is that when I print the results of an operation it always return the answer as an integer number. Why is that?
Thanks
Your use of atoi in the production converts the string to an integer.
Using atof will convert it to a floating point number.
If you want to separate the two, you'll need to change the matching rule for integers, and add one for floating point.
Change "%d" → "%f" in the file “bisonFile.y”. This uses a floating point format for printing the result. The fixed line should read:
| calclist exp EOL { printf("= %f\n", $2); }
In the file “flexFile.l” remove both definitions int yylval. bison outputs
YYSTYPE yylval;
automatically. YYSTYPE is the type of the semantic values. Because you want a floating point calculator, this shall be double. Note that YYSTYPE defaults to int. To change that, YYSTYPE must be defined when compiling the C-codes (from bison and flex) (see below).
Finally, as already stated by MIS, replace atoi() → atof(). The edited line in flexFile.l should read:
[0-9]+("."[0-9]+)? { yylval = atof(yytext); return NUMBER; }
For a novice the dependencies between flex and bison sources might be confusing. A minimal Makefile documents how the example can be compiled. Line 2 sets the semantic type for the scanner and the parser consistently:
calc: calc.o l.o
calc.o l.o: CFLAGS+=-DYYSTYPE=double
l.o: l.c f5.tab.h
calc.c f5.tab.h: bisonFile.y
bison -o $# --defines=f5.tab.h $^
l.c: flexFile.l f5.tab.h
flex -o $# $^
clean::
$(RM) calc calc.o calc.c f5.tab.h l.o l.c
That’ll do the trick.
I'm trying to study compiler construction on my own. I'm reading a book and this is one of the exercises (I want to stress that this is not homework, I'm doing this on my own).
The following grammar represents a simple arithmetic expressions in
LISP-like prefix notation
lexp -> number | ( op lexp-seq )
op -> + | * | +
lexp-seq -> lexp-seq lexp | lexp
For example, the expression (* (-2) 3 4) has a value of -24. Write
Yacc/Bison specification for a program that will compute and print
the value of expressions in this syntax. (Hint: this will require
rewriting the grammar, as well as the use of a mechanism for passing
the operator to an lexp-seq
I have solved it. The solution is provided below. However I have questions about my solution as well as the problem itself. Here they are:
I don't modify a grammar in my solution and it seems to be working perfectly. There are no conflicts when Yacc/Bison spec is converted to a .c file. So why is the author saying that I need to rewrite a grammar?
My solution is using a stack as a mechanism for passing the operator to an lexp-seq. Can someone suggest a different method, the one that will not use a stack?
Here is my solution to the problem (I'm not posting code for stack manipulation as the assumption is that the reader is familiar with how stacks work)
%{
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "linkedstack.h"
int yylex();
int yyerror();
node *operatorStack;
%}
%token NUMBER
%%
command : lexp { printf("%d\n", $1); };
lexp : NUMBER { $$ = $1; }
| '(' op lexp_seq ')'
{
int operator;
operatorStack = pop(operatorStack, &operator);
switch(operator) {
default:
yyerror("Unknown operator");
exit(1);
break;
case '+':
case '*':
$$ = $3;
break;
case '-':
$$ = -$3;
break;
}
}
;
op : '+' { operatorStack = push(operatorStack, '+'); }
| '-' { operatorStack = push(operatorStack, '-'); }
| '*' { operatorStack = push(operatorStack, '*'); }
;
lexp_seq : lexp_seq lexp
{
switch(operatorStack->data) {
default:
yyerror("Unrecognized operator");
exit(1);
break;
case '+':
$$ = $1 + $2;
break;
case '-':
$$ = $1 - $2;
break;
case '*':
$$ = $1 * $2;
break;
}
}
| lexp { $$ = $1; }
;
%%
int main(int argc, char** argv) {
int retVal;
init(operatorStack);
if (2 == argc && (0 == strcmp("-g", argv[1])))
yydebug = 1;
retVal = yyparse();
destroy(operatorStack);
return retVal;
}
int yylex() {
int c;
/* eliminate blanks*/
while((c = getchar()) == ' ');
if (isdigit(c)) {
ungetc(c, stdin);
scanf("%d", &yylval);
return (NUMBER);
}
/* makes the parse stop */
if (c == '\n') return 0;
return (c);
}
int yyerror(char * s) {
fprintf(stderr, "%s\n", s);
return 0;
} /* allows for printing of an error message */
Using a stack here is unnecessary if you rewrite the grammar.
One way is to use a different non-terminal for each operator:
command : lexp '\n' { printf("%d\n", $1); }
lexp : NUMBER
| '(' op_exp ')' { $$ = $2; }
op_exp : plus_exp | times_exp | minus_exp
plus_exp: '+' lexp { $$ = $2; }
| plus_exp lexp { $$ = $1 + $2; }
times_exp: '*' lexp { $$ = $2; }
| times_exp lexp { $$ = $1 * $2; }
minus_exp: '-' lexp { $$ = -$2; }
| minus_exp lexp { $$ = $1 - $2; }
I don't know if that is what your book's author had in mind. There are certainly other possible implementations.
In a real lisp-like language, you would need to do this quite differently, because the first object in an lexp could be a higher-order value (i.e. a function), which might even be the result of a function call, so you can't encode the operations into the syntax (and you can't necessarily partially evaluate the expression as you parse new arguments, either).
I recently started learning bison and I already hit a wall. The manual sections are a little bit ambiguous, so I guess an error was to be expected. The code below is the first tutorial from the official manual - The Reverse Polish Notation Calculator, saved in a single file - rpcalc.y.
/* Reverse polish notation calculator */
%{
#include <stdio.h>
#include <math.h>
#include <ctype.h>
int yylex (void);
void yyerror (char const *);
%}
%define api.value.type {double}
%token NUM
%% /* Grammar rules and actions follow. */
input:
%empty
| input line
;
line:
'\n'
| exp '\n' {printf ("%.10g\n", $1);}
;
exp:
NUM {$$ = $1; }
| exp exp '+' {$$ = $1 + $2; }
| exp exp '-' {$$ = $1 - $2; }
| exp exp '*' {$$ = $1 * $2; }
| exp exp '/' {$$ = $1 / $2; }
| exp exp '^' {$$ = pow ($1, $2); }
| exp 'n' {$$ = -$1; }
;
%%
/* The lexical analyzer */
int yylex (void)
{
int c;
/* Skip white space */
while((c = getchar()) == ' ' || c == '\t')
continue;
/* Process numbers */
if(c == '.' || isdigit (c))
{
ungetc (c, stdin);
scanf ("%lf", $yylval);
return NUM;
}
/* Return end-of-imput */
if (c == EOF)
return 0;
/* Return a single char */
return c;
}
int main (void)
{
return yyparse ();
}
void yyerror (char const *s)
{
fprintf (stderr, "%s\n", s);
}
Executing bison rpcalc.y in cmd returns the following error:
rpcalc.y:11.24-31: syntax error, unexpected {...}
What seems to be the problem?
The fault is caused by you using features that are new to the 3.0 version of bison, whereas you have an older version of bison installed. If you are unable to upgrade to version 3.0, it is an easy change to convert the grammar to using the features of earlier versions of bison.
The %define api.value.type {double} can be changed to a %type command, and the %empty command removed. The resulting bison program would be:
/* Reverse polish notation calculator */
%{
#include <stdio.h>
#include <math.h>
#include <ctype.h>
int yylex (void);
void yyerror (char const *);
%}
%type <double> exp
%token <double> NUM
%% /* Grammar rules and actions follow. */
input:
| input line
;
line:
'\n'
| exp '\n' {printf ("%.10g\n", $1);}
;
exp:
NUM {$$ = $1; }
| exp exp '+' {$$ = $1 + $2; }
| exp exp '-' {$$ = $1 - $2; }
| exp exp '*' {$$ = $1 * $2; }
| exp exp '/' {$$ = $1 / $2; }
| exp exp '^' {$$ = pow ($1, $2); }
| exp 'n' {$$ = -$1; }
;
%%
/* The lexical analyzer */
int yylex (void)
{
int c;
/* Skip white space */
while((c = getchar()) == ' ' || c == '\t')
continue;
/* Process numbers */
if(c == '.' || isdigit (c))
{
ungetc (c, stdin);
scanf ("%lf", $yylval);
return NUM;
}
/* Return end-of-imput */
if (c == EOF)
return 0;
/* Return a single char */
return c;
}
int main (void)
{
return yyparse ();
}
void yyerror (char const *s)
{
fprintf (stderr, "%s\n", s);
}
This runs in a wider range of bison versions.