如何检测部分未完成的令牌并将其从输入的两个后续部分获得的片段连接起来?
How to detect partial unfinished token and join its pieces that are obtained from two consequent portions of input?
我正在编写玩具终端,我在其中使用 Flex 来解析从 tty 获得的普通文本和控制序列。 Cocoa 机器的一个细节是它从 tty 读取 1024 字节的块,这样任何时候在我的 .lex 文件中描述的任何标记都可以分成两部分:标记的一些字节是前 1024 个块和剩余字节是下一个 1024 字节块的第一个字节。
所以我需要以某种方式:
- 首先检测这种情况:当一个令牌被分成两个1024字节的块时。
- 记住令牌的第一部分
- 当第二个 1024 块到达时,通过以某种方式将第一部分放在第二个块的前面来恢复第一部分。
我对 Flex 完全陌生,所以我正在寻找一种正确的方法来完成它。
我创建了 dumb simple lexer 来协助讨论。
我对这个演示的问题是:
我如何检测到最后一个 "FO"(未完成的 "FOO")令牌实际上是一个未完成的令牌,它不是我的语法的例外,但只需要它的 "O" 来自下一块输入?
您应该让 flex 进行读取。它旨在以这种方式工作;它将执行所有必要的缓冲,包括令牌在两个(或更多)输入缓冲区之间拆分的情况。
如果您不能简单地使用标准 fread
函数从 stdin 读取,那么您可以通过重新定义宏 YY_INPUT
来重新定义 flex 生成的解析器获取输入的方式。有关此宏的说明,请参阅 "Generated Parser" chapter of the flex manual。
我接受@rici 的回答是正确的,因为它给了我关于重新定义宏的重要提示 YY_INPUT。
在这个回答中,我只是想为像我这样的新手分享一些细节。
我使用 How to make YY_INPUT point to a string rather than stdin in Lex & Yacc (Solaris) 作为自定义 YY_INPUT 的示例,这使得我的人工示例可以正确处理部分标记。
要使 Flex 正确处理部分标记,输入不应包含 '\0' 符号,即扫描过程应为 "endless"。以下是 YY_INPUT 的重新定义:
int readInputForLexer(char *buffer, int *numBytesRead, int maxBytesToRead) {
static int Flip = 0;
if ((Flip++ % 2) == 0) {
strcpy(buffer, "FOO F");
*numBytesRead = 5; // IMPORTANT: this is 5, not 6, to cut off [=10=]
} else {
strcpy(buffer, "OO FOO");
*numBytesRead = 6; // IMPORTANT: this is 6, not 7, to cut off [=10=]
}
return 0;
}
在这个例子中,部分标记 F-OO 被 Flex 粘合成一个正确的标记:FOO。
正如@rici 在他的评论中指出的那样,停止扫描的正确方法是设置:*numBytesRead = 0
.
另请参阅@rici 对类似 SO 问题的另一个回答:Flex, continuous scanning stream (from socket). Did I miss something using yywrap()?。
有关详细信息,请参阅 my example。
我正在编写玩具终端,我在其中使用 Flex 来解析从 tty 获得的普通文本和控制序列。 Cocoa 机器的一个细节是它从 tty 读取 1024 字节的块,这样任何时候在我的 .lex 文件中描述的任何标记都可以分成两部分:标记的一些字节是前 1024 个块和剩余字节是下一个 1024 字节块的第一个字节。
所以我需要以某种方式:
- 首先检测这种情况:当一个令牌被分成两个1024字节的块时。
- 记住令牌的第一部分
- 当第二个 1024 块到达时,通过以某种方式将第一部分放在第二个块的前面来恢复第一部分。
我对 Flex 完全陌生,所以我正在寻找一种正确的方法来完成它。
我创建了 dumb simple lexer 来协助讨论。
我对这个演示的问题是:
我如何检测到最后一个 "FO"(未完成的 "FOO")令牌实际上是一个未完成的令牌,它不是我的语法的例外,但只需要它的 "O" 来自下一块输入?
您应该让 flex 进行读取。它旨在以这种方式工作;它将执行所有必要的缓冲,包括令牌在两个(或更多)输入缓冲区之间拆分的情况。
如果您不能简单地使用标准 fread
函数从 stdin 读取,那么您可以通过重新定义宏 YY_INPUT
来重新定义 flex 生成的解析器获取输入的方式。有关此宏的说明,请参阅 "Generated Parser" chapter of the flex manual。
我接受@rici 的回答是正确的,因为它给了我关于重新定义宏的重要提示 YY_INPUT。
在这个回答中,我只是想为像我这样的新手分享一些细节。
我使用 How to make YY_INPUT point to a string rather than stdin in Lex & Yacc (Solaris) 作为自定义 YY_INPUT 的示例,这使得我的人工示例可以正确处理部分标记。
要使 Flex 正确处理部分标记,输入不应包含 '\0' 符号,即扫描过程应为 "endless"。以下是 YY_INPUT 的重新定义:
int readInputForLexer(char *buffer, int *numBytesRead, int maxBytesToRead) {
static int Flip = 0;
if ((Flip++ % 2) == 0) {
strcpy(buffer, "FOO F");
*numBytesRead = 5; // IMPORTANT: this is 5, not 6, to cut off [=10=]
} else {
strcpy(buffer, "OO FOO");
*numBytesRead = 6; // IMPORTANT: this is 6, not 7, to cut off [=10=]
}
return 0;
}
在这个例子中,部分标记 F-OO 被 Flex 粘合成一个正确的标记:FOO。
正如@rici 在他的评论中指出的那样,停止扫描的正确方法是设置:*numBytesRead = 0
.
另请参阅@rici 对类似 SO 问题的另一个回答:Flex, continuous scanning stream (from socket). Did I miss something using yywrap()?。
有关详细信息,请参阅 my example。