flex-lexer - Flex 可重入从用户特定状态开始
问题描述
Flex在被调用时默认设置YY_STATE
为。我正在尝试制作一个可以从用户特定状态而不是初始状态开始的可重入扫描程序。INITIAL
yyscan_t
这是案例
/* comment start //not passed into flex
in comment //first line passed into flex
end of comment*/ //second line passed into flex
由于某些原因,这两条线被分别馈送到可重入扫描器中,并且这条线所属的 YY_STATE 是已知的。我需要的是在开始 lexing 之前将评论状态传递给reentrant flex 并切换YY_STATE
到。我的解决方法是在行首添加一个虚拟标记并将状态作为flex 传递。识别出虚拟令牌后,切换到特定状态。因此 flex 开始使用特定的 YY_STATE 对行进行词法分析。但是,在每行的开头添加一个虚拟标记非常耗时。COMMENT
in comment\n
yyextra
这是我以前称为可重入 flex 的方式:
yyscan_t scanner;
YY_BUFFER_STATE buffer;
yylex_init(&scanner);
buffer = yy_scan_string(inputStr, scanner);
yyset_extra(someStructure, scanner);
yylex(scanner);
yy_delete_buffer(buffer, scanner);
yylex_destroy(scanner);
是否可以在调用之前设置 YY_STATE yylex(scanner)
?
解决方案
如果您只yylex
为每个输入行调用一次,那么您可以添加一个额外的参数来yylex
提供要切换到的开始条件,并将开始条件设置在 yylex 的顶部。
但是没有简单的方法可以从 flex 文件外部引用开始条件,也没有一种方便的方法可以从yystate_t
对象中提取当前的开始条件。您声称拥有此信息的事实表明您在更改启动状态时将其存储在某处,因此您可以在启动时从同一位置恢复启动状态yylex
。存储信息的最简单的地方是yyextra
对象,所以这是这个示例代码的基础:
文件开始.int.h
/* This is the internal header file, which defines the extra data structure
* and, in this case, the tokens.
*/
#ifndef BEGIN_INT_H
#define BEGIN_INT_H
struct Extra {
int start;
};
enum Tokens { WORD = 256 };
#endif
文件开始.h
/* This is the external header, which includes the header produced by
* flex. That header cannot itself be included in the flex-generated code,
* and it depends on the internal header. So the order of includes here is
* (sadly) important.
*/
#ifndef BEGIN_H_
#define BEGIN_H_
#include "begin.int.h"
#include "begin.lex.h"
#endif
文件:begin.l
/* Very simple lexer, whose only purpose is to drop comments. */
%option noinput nounput noyywrap nodefault 8bit
%option reentrant
%option extra-type="struct Extra*"
%{
#include "begin.int.h"
/* This macro ensures that start condition changes are saved */
#define MY_BEGIN(s) BEGIN(yyextra->start = s)
%}
%x IN_COMMENT
%%
/* See note below */
BEGIN (yyextra->start);
"/*" MY_BEGIN(IN_COMMENT);
[[:alnum:]]+ return WORD;
[[:space:]]+ ;
. return yytext[0];
<IN_COMMENT>{
"*/" MY_BEGIN(INITIAL);
.|[^*]+ ;
}
笔记:
在第一个模式之后和第一个模式之前的任何缩进代码%%
都插入到 ; 的开头yylex
。唯一在它之前执行的是对象的一次性初始化(yystate_t
如有必要)。
文件开始.main.c
/* Simple driver which creates and destroys a scanner object for every line
* of input. Note, however, that it reuses the extra data object, which holds
* persistent information (in this case, the current start condition).
*/
#include <stdio.h>
#include "begin.h"
int main ( int argc, char * argv[] ) {
char* buffer = NULL;
size_t buflen = 0;
struct Extra my_extra = {0};
for (;;) {
ssize_t nr = getline(&buffer, &buflen, stdin);
if (nr < 0) break;
if (nr == 0) continue;
yyscan_t scanner;
yylex_init_extra(&my_extra, &scanner);
/* Ensure there are two NUL bytes for yy_scan_buffer */
if (buflen < nr + 2) {
buffer = realloc(buffer, nr + 2);
buflen = nr + 2;
}
buffer[nr + 1] = 0;
YY_BUFFER_STATE b = yy_scan_buffer(buffer, nr + 2, scanner);
for (;;) {
int token = yylex(scanner);
if (token == 0) break;
printf("%d: '%s'\n", token, yyget_text(scanner));
}
yy_delete_buffer(b, scanner);
yylex_destroy(scanner);
}
return 0;
}
建造:
flex -o begin.lex.c --header-file begin.lex.h begin.l
gcc -Wall -ggdb -o begin begin.lex.c begin.main.c
推荐阅读
- list - Haskell 是否有一个函数可以创建将函数应用于列表的每个变体
- databricks - 删除 Databricks Notebook 的所有单元格
- python - 使用 Python 将英文单词转换为数字向量
- authentication - 如何将 UWP 应用的身份验证从 OneDrive SDK 迁移到 Graph
- javascript - JavaScript:检测层次图中的循环
- python - 如何在 R/Python 中从 GPS 数据集中检测停止点
- r - R:使用 eval() 的 dbplyr
- excel - 宏中的计数
- python - 我想从我的最后一行之后检测圆圈并指定它的位置
- javascript - 如何在Vue3.0中通过双击打开或关闭自动播放?