题
我试图使用flex和bison,创建一个过滤器,因为我想要得到某些语法因素从一个复杂的语言。我的计划是使用flex+野牛认识的语法,以及倾倒出的位置因素的兴趣。(然后用脚本抢文本根据地点倾倒。)
我发现flex可以支持一个野牛功能叫做野牛的地点,但它是如何工作。我试图例如在flex的文件,似乎yylloc不是自动设定的flex,我总是能得到 (1,0)-(1,0)
.可以flex计算的每个标记的位置自动?如果不是,什么样的接口功能定义我到执行?是否有任何例子吗?
任何更好解决方案有关的工具?
最好的问候, 凯文
编辑:
现在的接口yylex转到:
int yylex(YYSTYPE * yylval_param,YYLTYPE * yylloc_param );
野牛手册》没有规定如何语法分析程序应该执行正确地设定yylloc_param.对我来说是很难到手动追踪列号码的每个标记。
解决方案
看一看部 3.6野牛手动 - 这似乎包括一些细节的位置。与您在Flex手册发现什么组合,这可能是足够的。
其他提示
在函数yylex声明可能改变,因为您使用的可重入的或纯的解析器。好像网络上的许多文件显示,如果你想野牛地点工作它是必需的,但它不是必需的。
我需要行号太,发现野牛文档在这方面混淆。 简单的解决办法(使用全局变量yylloc): 在您的野牛文件只需添加%位置指令:
%{
...
%}
%locations
...
%%
...
在您的词法分析:
%{
...
#include "yourprser.tab.h" /* This is where it gets the definition for yylloc from */
#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno;
%}
%option yylineno
...
%%
...
在YY_USER_ACTION宏“称”每个令牌操作和更新yylloc之前。 现在,您可以使用@N / @ $规则是这样的:
statement : error ';' { fprintf(stderr, "Line %d: Bad statement.\n", @1.first_line); }
,或使用yylloc全局变量:
void yyerror(char *s)
{
fprintf(stderr, "ERROR line %d: %s\n", yylloc.first_line, s);
}
我喜欢的Shlomi的答案。
在另外我寻找更新列位置为好。发现 http://oreilly.com/linux/excerpts/9780596155971/error-报告 - recovery.html其阅读施洛米的回答后更有意义。
不幸的是,页yylloc上的错字。我已经简化下面一点它。
在解析器中添加:
%locations
在您的词法分析:
%{
#include "parser.tab.h"
int yycolumn = 1;
#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno; \
yylloc.first_column = yycolumn; yylloc.last_column = yycolumn + yyleng - 1; \
yycolumn += yyleng; \
yylval.str = strdup(yytext);
%}
%option yylineno
有可能是一些与列位置事情不严格遵守列的轨迹而只是不断增加。这只是我的无知和appologize如果它混淆了人。我目前使用的列保持一个文件的字符数这在我的情况比列位置更有利。
希望有所帮助。
无论bison
也不flex
自动更新yylloc
,但它实际上是不难做到这一点你自己,如果你知道的伎俩。
诀窍实施yylloc
支持,尽管yyparse()
声明yylloc
,它永远不会改变它。这意味着,如果你修改yylloc
在一个调用词法分析器,你会在下次调用找到它的值相同。因此,yylloc
将包含最后一个记号的位置。由于最后一个记号的一端是与当前令牌的开始,你可以使用旧yylloc
值,以帮助您确定新的值。
在换句话说,yylex()
不应计算 yylloc
;它应该更新 yylloc
。
要更新yylloc
,首先要复制last_
值first_
,然后更新last_
值以反映刚刚匹配令牌的长度。 (这不是令牌的strlen()
;它的线条和柱长度)。我们可以在YY_USER_ACTION
宏,它只是在执行任何词法动作之前调用做到这一点;确保,如果一个规则相匹配,但它并没有返回值(例如,跳过空白或批注的规则),非标记的位置被跳过,而不是被包括在实际令牌的开头,或失去的方式,使所述位置跟踪不准确的。
下面是意味着一个可重入解析器的一个版本;你可以通过交换->
运营商.
修改它的非折返解析器:
#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++; \
} \
}
如果您愿意,您可以改为把这些代码的功能,使宏调用的功能,但是这两种技术是等价的。
Shomi的回答是最简单的解决方案,如果你只关心保持行号。但是,如果你也想列数,那么你需要让他们的轨道。
要做到这一点的方法之一是增加yycolumn = 1
规则无处不在换行显示出来(如大卫·埃尔森的答复建议),但如果你不希望保留换行符可能出现的所有地方(空白,评论等的轨道..)替代在每个动作开始检查yytext
缓冲液:
static void update_loc(){
static int curr_line = 1;
static int curr_col = 1;
yylloc.first_line = curr_line;
yylloc.first_column = curr_col;
{char * s; for(s = yytext; *s != '\0'; s++){
if(*s == '\n'){
curr_line++;
curr_col = 1;
}else{
curr_col++;
}
}}
yylloc.last_line = curr_line;
yylloc.last_column = curr_col-1;
}
#define YY_USER_ACTION update_loc();
最后,有一点要注意的是,一旦你开始用手跟踪列数的,你也可能还跟踪行号在同一个地方,而不是使用Flex的yylineno
选项费心了。
因此,我得到了这个"工作",但是与一些额外的步骤(我可能忽略了他们,在这里...抱歉在这种情况下):
在 分析器。y, 我不得不说:
#define YYLEX_PARAM &yylval, &yylloc
甚至有
%locations
和bison --locations
, ,获得到通过的数据。在 语法分析程序.我 我不得不用
->
而不是的.
对于yylloc
还在 语法分析程序.我, 我重列行动:
[\n] { yycolumn = 1; }
显然更加复杂, \r
等等,但至少我得到了它的工作。
我觉得我设法使它工作(幸得野牛手册的 ltcalc词法分析器)。 默认情况下,野牛创建包含yylloc
{ first_line, first_column , last_line , last_column }
我们只需要在我们的词法分析器来更新这些值。例如:
[ \t] { ++yylloc.last_column; }
[\n] { yyloc.last_column = 0; return EOL; }
[a-zA-Z]+ {
yylloc.last_column += strlen(yytext);
return IDENTIFIER;
}
现在在野牛,来检索这些字段:
statement : IDENTIFIER '=' expression
{ printf("%d - %d\n", @1.last_line, @1.last_column); }
默认情况下,这些字段都被初始化为一个,我们应该初始化列字段设为零,否则他们会报告错误的列。
这是除了施洛米的回答是:
如果您正在使用%野牛定义api.pure创建一个可重入解析器,你还需要指定在柔性%选择野牛位置。这是因为在可重入解析器yylloc不是全局变量,并且需要被传递到词法分析
因此,在解析器:
%define api.pure
%locations
在词法分析器:
#include "yourprser.tab.h"
#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno;
%option bison-locations
%option yylineno