lex&yacc获得当前位置

Var*_*yan 1 compiler-construction parsing lex lexical-analysis

在lex&yacc中有一个名为YY_INPUT的宏,可以重新定义,例如以这种方式

#define YY_INPUT(buf,result,maxlen) do { \
 const int n = gzread(gz_yyin, buf, maxlen); \                                                                              
 if (n < 0) { \
       int errNumber = 0; \
       reportError( gzerror(gz_yyin, &errNumber)); } \
     \
     result = n > 0 ? n : YY_NULL; \
  } while (0)
Run Code Online (Sandbox Code Playgroud)

我有一些叫做YYACCEPT宏的语法规则.如果在YYACCEPT之后我调用了gztell(或ftell),那么我得到一个错误的数字,因为解析器已经读取了一些不必要的数据.

那么如果我有一些叫做YYACCEPT的规则,我怎么能得到当前的位置(一个坏的解决方案是逐个字符地阅读)

(我已经做过这样的事情:

#define YY_USER_ACTION do { \
        current_position += yyleng; \
} while (0)   
Run Code Online (Sandbox Code Playgroud)

但似乎不起作用)

ric*_*ici 5

你必须自己跟踪偏移量.一个简单而烦人的解决方案是:

offset += yyleng;
Run Code Online (Sandbox Code Playgroud)

每个弹性动作中.幸运的是,您可以通过定义YY_USER_ACTION宏来隐式地执行此操作,该宏在令牌操作之前执行.

这可能仍然不适合你的语法,因为bison通常会提前读取一个标记.因此,您还需要将值附加offset到每个词法标记,最方便的是使用location facility(yylloc).

修改:添加了有关位置跟踪的更多详情.

以下未经过测试.您应该阅读有关位置跟踪flexbison手册和手册中的章节.

yylloc全局变量和它的默认类型被包括在所产生的野牛代码如果使用--locations命令行选项或%locations指令,或者如果你简单地指的位置值在一些规则,使用该@语法,这是类似于$句法(即是,@n是语义值为的右侧对象的位置值$n.不幸的是,yylloc使用ints 的默认类型,其宽度不足以容纳文件偏移量,尽管您可能没有计划解析重要的文件.无论如何,它很容易改变; 你只需要在文件顶部#defineYYLTYPEbison.默认YYLTYPE为:

typedef struct YYLTYPE
     {
       int first_line;
       int first_column;
       int last_line;
       int last_column;
     } YYLTYPE;
Run Code Online (Sandbox Code Playgroud)

对于最小的修改,我建议保持名称不变; 否则你还需要修复文件中的YYLLOC_DEFAULTbison.默认YYLLOC_DEFAULT确保非终端获得一个位置值,其first_linefirst_column成员来自于非终端的RHS它的第一个元素,并last_linelast_column成员来自最后一个元素.由于它是一个宏,它将适用于各种成员的任何可分配类型,因此将column成员更改为long,size_t或者offset_t,在您认为合适时:

#define YYLTYPE yyltype;
typedef struct yyltype {
  int first_line;
  offset_t first_column;
  int last_line;
  offset_t last_column;
} yyltype;
Run Code Online (Sandbox Code Playgroud)

然后在您的flex输入中,您可以定义YY_USER_ACTION宏:

offset_t offset;
extern YYLTYPE yylloc;

#define YY_USER_ACTION         \
  offset += yyleng;            \
  yylloc.last_line = yylineno; \
  yylloc.last_column = offset;
Run Code Online (Sandbox Code Playgroud)

与所有的完成,相应的初始化,你应该能够使用适当@n.last_columnACCEPT规则来提取在接受输入的最后一个记号的末尾的偏移量.