3

On Bison, it's possible yylval be a struct instead a union ? I know that i can define yylval as union with %union{} but is there a way to define yylval as struct ? to return the line and the string of a identifier for exemple and access these information on a action of some gramar rule on bison.

Joao Pedro
  • 61
  • 6

2 Answers2

3

Yes, you can #define YYSTYPE to be any type you want instead of using %union. However, it is rarely useful to do so1 -- if you want source position info, you're much better off using %position in combination with %union.

Its also possible (and common) to use structs within the %union declaration. This makes it easy for some rules to return multiple values (effectively).


1The main problem being that if you use %type to specify the use of one struct field, its painful to use other fields in the same action. You need to do everything manually, thus losing the benefit of bison's union type checking

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
1

If you want to keep location information (line number and column number) for your tokens, you can use Bison's location facility, which keeps a location object for each token and non-terminal separately from the semantic value. In an action, you refer to a symbol's location as @n.

The location stack is created and maintained automatically by bison if it sees that you have referred to a location anywhere in a rule.

By default, the location datatype is:

typedef struct YYLTYPE {
  int first_line;
  int first_column;
  int last_line;
  int last_column;
} YYLTYPE;

The location information for tokens must be set by the lexer. If you are using the default API, it is stored in the global variable yylloc. The parser will create location information for non-terminals by using the range from the beginning of the first item of a production up to the end of the last item. (For empty productions, a zero-length location object is generated, starting and ending with the start position of the lookahead token.)

Both of these defaults can be overridden if necessary. See the Bison manual for details.

Flex will track line numbers if asked to with %option yylineno, but it does not track column positions, which is a bit annoying. Also, yylloc requires both a starting and an ending line number; yylineno in a flex action will be the line number at the end of the token. Most commonly, you will use the YY_USER_ACTION macro to maintain the value of yylloc; an example implementation (taken from this answer, which you should read if you use this code) is:

%option yylineno
%{
#define YY_USER_ACTION                                       \
  yylloc.first_line = yylloc.last_line;                      \
  yylloc.first_column = yylloc.last_column;                  \
  if (yylloc.first_line == yylineno)                         \
     yylloc.last_column += yyleng;                           \
  else {                                                     \
     int col;                                                \
     for (col = 1; yytext[yyleng - col] != '\n'; ++col) {}   \
     yylloc.last_column = col;                               \
     yylloc.last_line = yylineno;                            \
  }
%}
rici
  • 234,347
  • 28
  • 237
  • 341
  • I want to save both yytext and token integer in yylval, for example `#define YYSTYPE struct { int token; char *literal };`, is it possible? – linrongbin Jan 08 '20 at 10:06
  • @linrongbin: Sure. Don't use `#define YYSTYPE`, though; that will surely get you into trouble. You need to make sure the declarations are visible wherever they are necessary, which means they should be in the bison-generated header. To achieve that, put the `struct` declaration (`struct MyToken { ... }`) into a `code requires` block in your bison definition, and then use `%define api.value.type {struct MyToken}`, as described in the [bison manual](https://www.gnu.org/software/bison/manual/bison.html#Type-Generation). If you need a more detailed answer, ask a new question. – rici Jan 08 '20 at 14:39