How does flex support bison-location exactly?

前端 未结 8 1145
轮回少年
轮回少年 2020-12-24 07:38

I\'m trying to use flex and bison to create a filter, because I want get certain grammar elements from a complex language. My plan is to use flex + bison to recognise the gr

8条回答
  •  忘掉有多难
    2020-12-24 08:06

    Neither bison nor flex updates yylloc automatically, but it's actually not difficult to do it yourself—if you know the trick.

    The trick to implementing yylloc support is that, even though yyparse() declares yylloc, it never changes it. That means that if you modify yylloc in one call to the lexer, you'll find the same values in it at the next call. Thus, yylloc will contain the position of the last token. Since the last token's end is the same as the current token's start, you can use the old yylloc value to help you determine the new value.

    In other words, yylex() should not calculate yylloc; it should update yylloc.

    To update yylloc, we must first copy the last_ values to first_, and then update the last_ values to reflect the length of the just-matched token. (This is not the strlen() of the token; it's the lines-and-columns length.) We can do this in the YY_USER_ACTION macro, which is called just before any lexer action is performed; that ensures that if a rule matches but it doesn't return a value (for instance, a rule skipping whitespace or comments), the location of that non-token is skipped, rather than being included at the beginning of the actual token, or lost in a way that makes the location tracking inaccurate.

    Here's a version meant for a reentrant parser; you could modify it for a non-reentrant parser by swapping the -> operators for .:

    #define YY_USER_ACTION \
        yylloc->first_line = yylloc->last_line; \
        yylloc->first_column = yylloc->last_column; \
        for(int i = 0; yytext[i] != '\0'; i++) { \
            if(yytext[i] == '\n') { \
                yylloc->last_line++; \
                yylloc->last_column = 0; \
            } \
            else { \
                yylloc->last_column++; \
            } \
        }
    

    If you'd prefer, you could instead put that code in a function and make the macro call the function, but the two techniques are equivalent.

提交回复
热议问题