在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_lineno
和yy_bs_column
字段在初始化为1后未触及任何位置0,分别。我是否需要在我的lexing定义中将其自身增加?
答案 0 :(得分:3)
flex
缓冲区状态的数据成员是私有的;你不应该尝试使用它们。特别是,yy_bs_lineno
和yy_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;
}