如何在解析过程中获取光标位置?
How to get the cursor location during parsing?
我为 Packcc 解析器生成器做了一个最小的例子。
在这里,解析器必须识别浮点数或整数。
我尝试打印检测到的数字的位置。为简单起见,没有
line/column 计数,只是来自“ftell”的数字。
%auxil "FILE*" # The type sent to "pcc_create" for access in "ftell".
test <- line+
/
_ EOL+
line <- num _ EOL
num <- [0-9]+'.'[0-9]+ {printf("Float at %li\n", ftell(auxil));}
/
[0-9]+ {printf("Integer at %li\n", ftell(auxil));}
_ <- [ \t]*
EOL <- '\n' / '\r\n' / '\r'
%%
int main()
{
FILE* file = fopen("test.txt", "r");
stdin = file;
if(file == NULL) {
// try to open.
puts("File not found");
}
else {
// parse.
pcc_context_t *ctx = pcc_create(file);
while(pcc_parse(ctx, NULL));
pcc_destroy(ctx);
}
return 0;
}
要解析的文件可以是
2.0
42
命令可以
packcc test.peg && cc test.c && ./a.out
问题是游标值总是在文件末尾,无论数字是多少
位置。
如果不仔细查看生成的代码,解析器似乎会坚持在执行任何操作之前将整个文本读入内存。这对于这个语法来说似乎是不必要的,而且它肯定不是典型的生成词法扫描器的工作方式。这特别奇怪,因为生成的扫描器似乎使用 getchar
一次读取一个字节,如果您打算读取整个文件,这不是很有效。
公平地说,您也无法在 flex-generated 扫描仪中使用 ftell
,除非您强制扫描仪进入交互模式。 (原始的 AT&T lex 也一次读取一个字符,将从 ftell
中为您提供合理的值。但您不太可能再找到用它构建的扫描仪。)
Flex 会给你错误的答案,因为它故意以其缓冲区大小(通常为 8k)的块读取输入。这比 character-at-a-time 阅读效率高得多。但它不适用于交互式环境——例如,您直接从用户输入解析的地方——因为您不想阅读超出用户键入行尾的内容。
您必须询问维护 packcc 的人他们维护源位置的预期方法是什么。他们可能内置了一些东西。
可以通过特殊变量检索位置。
在上面的示例中,“ftell”必须替换为“$0s”或“$0e”。
$0s 是匹配模式的开始,$0e 是匹配模式的结束。
我为 Packcc 解析器生成器做了一个最小的例子。 在这里,解析器必须识别浮点数或整数。 我尝试打印检测到的数字的位置。为简单起见,没有 line/column 计数,只是来自“ftell”的数字。
%auxil "FILE*" # The type sent to "pcc_create" for access in "ftell".
test <- line+
/
_ EOL+
line <- num _ EOL
num <- [0-9]+'.'[0-9]+ {printf("Float at %li\n", ftell(auxil));}
/
[0-9]+ {printf("Integer at %li\n", ftell(auxil));}
_ <- [ \t]*
EOL <- '\n' / '\r\n' / '\r'
%%
int main()
{
FILE* file = fopen("test.txt", "r");
stdin = file;
if(file == NULL) {
// try to open.
puts("File not found");
}
else {
// parse.
pcc_context_t *ctx = pcc_create(file);
while(pcc_parse(ctx, NULL));
pcc_destroy(ctx);
}
return 0;
}
要解析的文件可以是
2.0
42
命令可以
packcc test.peg && cc test.c && ./a.out
问题是游标值总是在文件末尾,无论数字是多少 位置。
如果不仔细查看生成的代码,解析器似乎会坚持在执行任何操作之前将整个文本读入内存。这对于这个语法来说似乎是不必要的,而且它肯定不是典型的生成词法扫描器的工作方式。这特别奇怪,因为生成的扫描器似乎使用 getchar
一次读取一个字节,如果您打算读取整个文件,这不是很有效。
公平地说,您也无法在 flex-generated 扫描仪中使用 ftell
,除非您强制扫描仪进入交互模式。 (原始的 AT&T lex 也一次读取一个字符,将从 ftell
中为您提供合理的值。但您不太可能再找到用它构建的扫描仪。)
Flex 会给你错误的答案,因为它故意以其缓冲区大小(通常为 8k)的块读取输入。这比 character-at-a-time 阅读效率高得多。但它不适用于交互式环境——例如,您直接从用户输入解析的地方——因为您不想阅读超出用户键入行尾的内容。
您必须询问维护 packcc 的人他们维护源位置的预期方法是什么。他们可能内置了一些东西。
可以通过特殊变量检索位置。 在上面的示例中,“ftell”必须替换为“$0s”或“$0e”。 $0s 是匹配模式的开始,$0e 是匹配模式的结束。