Bison yacc中获取行号的方法

Bison yacc中获取行号的方法,bison,yacc,Bison,Yacc,在yacc中获取行号的不同方式有哪些。我知道yylineno,但当yacc读取前瞻令牌时,它可以在1之前关闭 我在yacc中使用yytext时也遇到了同样的问题。它没有给出预期的令牌。我在lex中使用了yylval.str来完成这个任务。有没有类似的方法可以得到准确的行号 Bison中是否有更好的选项可以使处理更简单和准确扫描仪的作用是生成一系列词汇标记,每个标记都有一个类型、一个语义值,可能还有一个位置。解析器接收该令牌流,并将其处理为输入的结构表示 应该清楚的是,在解析器中,“最后扫描的语义

在yacc中获取行号的不同方式有哪些。我知道yylineno,但当yacc读取前瞻令牌时,它可以在1之前关闭

我在yacc中使用yytext时也遇到了同样的问题。它没有给出预期的令牌。我在lex中使用了yylval.str来完成这个任务。有没有类似的方法可以得到准确的行号


Bison中是否有更好的选项可以使处理更简单和准确

扫描仪的作用是生成一系列词汇标记,每个标记都有一个类型、一个语义值,可能还有一个位置。解析器接收该令牌流,并将其处理为输入的结构表示

应该清楚的是,在解析器中,“最后扫描的语义值”几乎没有价值,特别是因为解析器通常需要要求扫描器至少向前看一个标记,以决定如何继续。但更一般地说,解析器操作将组合关于一系列标记(以及一系列已经减少的产品)的信息,因此在操作中没有“一个值”是有意义的

类似地,每个令牌在输入中都有一个位置,如果解析器需要将位置与语法特征关联,那么它需要能够引用任何给定令牌的位置

Bison通过允许扫描器填写语义值(
yylval
),简化了这一过程。location对象称为
yylloc
,与语义值不同,每个标记的类型通常相同。如果Bison源使用位置,它将创建一个与语义值堆栈同步的位置对象堆栈。在规则中,令牌(或非终端)的语义值可以称为
$1
$2
,等等。;类似地,令牌/非终端的位置将是
@1
@2

你不需要告诉野牛收集位置信息。如果您只是在任何解析器操作中使用某个位置引用(
@n
),它将自动发生

事实上,您不需要在解析器中做太多工作来利用位置信息,因为默认值通常就足够了。除非定义预处理器宏
YYLTYPE
,否则称为
YYLTYPE
的位置对象类型将声明如下:

typedef struct YYLTYPE {
  int first_line;
  int first_column;
  int last_line;
  int last_column;
} YYLTYPE;
声明将被放入生成的头文件中,以便扫描器也可以使用它。
YYLTYPE
结构反映了一个事实,即令牌——更重要的是,非终端——跨越源文件中的一系列位置

非终端的位置结构也将由生成的解析器自动填充,尽管您可以通过在解析器操作中分配给
@$
来自由修改它。默认情况下,取
@1
中的
第一行
第一列
字段,取
@n
中的
最后一行
最后一列
字段,其中n是右侧的符号数。换句话说,当您减少生产时,生成的位置将跨越表示生产标记的所有源文本

虽然
yylloc
同时包含行和列信息,但不需要使用列数据。最方便的方法是将这些字段设置为0,以防您希望在解析器的某个更高版本中使用它们;您可以通过重新定义
YYLTYPE
来减少位置堆栈的开销,但是您还需要重写默认位置操作,因为它引用了那些命名字段

填充
yylloc
对象完全是扫描仪的责任,不幸的是,flex对您帮助不大。如果您要求,Flex将维护
yylineno
%option yylineno
),但它不会填充
yylloc
,因此您需要自己完成。幸运的是,flex允许您定义宏。该宏插入每个flex操作的开头,可用于将位置信息复制到
yylloc

作为一个简单的例子,如果您的令牌没有跨越多行(或者您不关心跨越多行的令牌的起始行),您可以简单地将其放在flex定义的序言中:

#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno;
并使用启用
yylineno
跟踪

%option yylineno
完成此操作后,在对flex或bison定义没有其他更改的情况下,您将能够编写以下操作:

assignment: IDENTIFIER '=' expression {
               printf("%s is defined at line %d\n", $1, @1.first_line);
            }
请注意,由于上述规则引用了
标识符
标记的位置,因此
表达式
使用了多少行并不重要。您可以更精确地使用默认设置
@$

assignment: IDENTIFIER '=' expression {
               printf("%s is defined in lines %d to %d\n",
                      $1, @$.first_line, @$.last_line);
            }