如何在Flex中使用`yy_bs_lineno`和`yy_bs_column`?

时间:2014-11-10 22:41:12

标签: flex-lexer

在Flex生成的C代码中,我看到YY_BUFFER_STATE被声明为以下

struct yy_buffer_state
{
    ...
    int yy_bs_lineno; /**< The line count. */
    int yy_bs_column; /**< The column count. */
    ...
}

我想向用户公布lexing错误以及错误令牌的行号和列,但yy_bs_linenoyy_bs_column字段在初始化为1后未触及任何位置0,分别。我是否需要在我的lexing定义中将其自身增加?

1 个答案:

答案 0 :(得分:3)

flex缓冲区状态的数据成员是私有的;你不应该尝试使用它们。特别是,yy_bs_linenoyy_bs_column成员在重入扫描程序中由flex使用。

如果您使用:

%option yylineno

然后flex会跟踪变量yylineno中的当前行号。

请注意,yylineno是令牌后面第一个字符行的行号。因此,如果令牌包含(或者甚至以换行符)换行符,yylineno的值将会有点欺骗性。如果您有多行令牌(例如,多行字符串常量),则值得保留yylineno的先前值。

Flex非常聪明地计算行数。例如,它知道哪些令牌不能与换行符匹配,因此在找到其中一个令牌后,它不需要重新扫描输入。让flex为你做的工作几乎总是一个好主意。

不幸的是,跟踪列没有类似的简单方法,但有一些方面有帮助。其中一个是宏钩YY_USER_ACTION。如果您定义此宏,它将在每个操作之前执行。因此,您可以使用它来保持您的行号信息同步。

这是我可以剪切和粘贴的最简单的例子:

%{
#  include <stdio.h>

/* WARNINGS:
 *   1. Reentrant scanners define yycolumn
 *      Only use this in a non-reentrant scanner
 *   2. This will not work if you use `yyless()` or `yymore()`.
 */
int yycolumn = 1;

/* Forward declarations */
void report(const char* ttype, int line, int column);

/* This is executed before every action. */
#define YY_USER_ACTION                                                   \
  start_line = prev_yylineno; start_column = yycolumn;                   \
  if (yylineno == prev_yylineno) yycolumn += yyleng;                     \
  else {                                                                 \
    for (yycolumn = 1; yytext[yyleng - yycolumn] != '\n'; ++yycolumn) {} \
    prev_yylineno = yylineno;                                            \
  }

%}
%option noyywrap nounput noinput
%option yylineno

%%
   /* Any indented text before the first rule goes at the top of the lexer.  */
   int start_line, start_column;
   int prev_yylineno = yylineno;

[[:space:]]+              { }
[[:alpha:]_][[:alnum:]_]* { report("ID", start_line, start_column);
                            return 258; 
                          }
["]([^"]|\\.)*["]         { report("STR", start_line, start_column);
                            return 259;
                          }
.                         { report("SYM", start_line, start_column);
                            return yytext[0];
                          }
%%
void report(const char* t, int l, int c) {
  printf("Encountered %s \"%.*s\" at %d:%d\n", t, (int)yyleng, yytext, l, c);
}

int main(int argc, char** argv) {
  while (yylex() > 0) {}
  return 0;
}