将 flex 状态与 bison 同步(HTTP 解析器)
Synchronize flex states with bison (HTTP parser)
我正在尝试使用 flex bison 编写 HTTP 解析器。我的第一个想法是只对最基本的标记进行 lex,然后使用解析器将它们组合起来。例如在 HTTP header 中会有 GET
、POST
或 PUT
以及 URL
和 HTTP_VERSION
等标记。现在的问题是, URL 包含例如字符串 "POST"
和词法分析器无法区分 URL
标记中的 "POST"
或实际 POST
标记中的 "POST"
。
该问题的解决方案是使用 flex 启动条件状态,根据预期启用和禁用特定模式。在 INITIAL
状态下找到 GET
、POST
等标记后,词法分析器切换到另一个只匹配 URL
的状态。这个解决方案虽然感觉不对。感觉就像在属于解析器的词法分析器中实现逻辑(比如“正好有一个 GET
、POST
、... 标记后跟一个 URL
)。
这引出了我的问题:
有没有一种方法可以在 bison 解析器和 flex 词法分析器之间“同步”,以便我可以根据 bison 期望的下一个标记来更改词法分析器状态?
P.S.:
我不太了解语法 类 和解析语言背后的理论知识。在我看来,解析 HTTP header 甚至不需要像 bison 这样的无上下文语言解析器。 HTTP是不是正则语言,我可以用正则表达式解析?
使用 Bison 来解析 HTTP header 不仅仅是矫枉过正;这是工具和问题之间的不匹配。这就像尝试使用 Photoshop 写一篇文章。 Photoshop是一种高度复杂的工具,在熟练的操作者手中,它可以使任何图像看起来都很漂亮,从某种意义上说,一篇文章就是一个图像(或一系列图像)。但这个任务很荒谬。当然,Photoshop 有文本块。但是您不想专注于每个矩形文本块。您想书写,让文字从一页流到另一页,这是 Photoshop 模型之外的东西,无论该工具多么复杂。
Bison 和 Flex 旨在解析具有复杂语法的语言,在这种语言中,输入可以首先被分成词汇单元(标记),而不考虑它们的语法上下文。如果您发现自己在问诸如“我怎样才能将预期输入的性质传达给词法分析器?”之类的问题,那么您可能使用了错误的工具。当然,Flex 是一个强大的工具,它具有的特性使其能够适应词汇上下文中的微小变化。但这些应该是特例。
像 HTTP 这样的协议被设计成易于分析。您既不需要解析器也不需要词法分析器来查看行首是少数几个可能的动词中的哪一个,或者将以下字符串提取到第一个 space 字符。您不需要进行复杂的错误分析和恢复,您甚至不应该尝试,因为它会泄露信息并可能打开漏洞。如果一个字符无法解析,就发送一个400并停止读取。
好的工具可以简化其设计领域内问题的解决。优秀工程师的部分技能是识别哪些工具适用于给定的问题。在这种情况下,Bison/Flex 不是工具。
我也不确定正则表达式有多大帮助,因为 HTTP 解析中的主要挑战是处理间歇性、异步、有点不可靠且容易受到攻击的输入流。与 Flex 一样,大多数正则表达式库都需要一个已经明确终止的输入字符串,而通过 Internet 传输的协议则不是这种情况。
构建从 Bison 解析器到 Flex 扫描器的反向通道是可能的,但这不是尝试的地方。所以我不愿意尝试在这种情况下解释这些技术。
HTTP 是一种常规语言。从事实中我们可以看出,它可以用有限状态机来解析。理论上应该可以(不要引用我的话)用正则表达式匹配整个 HTTP 消息。这种解析方法的问题在于,常见的正则表达式语言没有复杂的捕获选项。通常我们可以捕获单个子匹配并将它们存储起来供以后使用,但是在 bison 中没有像 callback-like 方法这样的东西,在这种方法中可以根据对某些子模式的识别指定任意操作。
bison 和 flex 不是解决此问题的正确工具的原因(如其他答案中所述)在于一个非常基本的 属性,它将 HTTP 语言与典型的编程语言区分开来,其中 flex 和 bison通常使用:
编程语言由符号字母表组成。这意味着例如可以将关键字视为该字母表中的单个元素,并且可以将输入的字符流明确地转换为标记流。这正是词法分析器的目的,它充当从一个字母表到另一个字母表的翻译器。在某些情况下,词法分析器还充当解析器并且需要更多的内部逻辑,而不是简单地将输入序列转换为标记。这些情况中最常见的一种是评论。评论中的关键字不再发出标记。
另一方面,对于 HTTP,字母表只是输入字符。使用词法分析器没有多大意义。 OP 提到的关于 flex 和 bison 之间通信的问题源于这样一个事实,即他试图将语言的解析(这是一个单一的问题)分成两部分。 Flex 不是 解析器,不适合解析。解决方案是忽略词法分析器阶段,因为它不是必需的。 Bison 非常有能力为常规语言生成解析器,可用于解析 HTTP。
这让我想到了最后一点。即使 bison 能够生成常规语言解析器,它也不是最合适的工具。 Bison 可以为 context-free 种语言生成解析器。这些是使用带有堆栈的有限状态机进行解析的。对于解析一种常规语言,不需要堆栈,因为没有需要“记住”的嵌套结构。因此,bison 生成的 HTTP 解析器很可能不会像常规语言解析器生成器生成的解析器那样优化。遗憾的是,我找不到一个纯正则语言解析器生成器,但这样的东西将是生成 HTTP 解析器的首选工具。
我正在尝试使用 flex bison 编写 HTTP 解析器。我的第一个想法是只对最基本的标记进行 lex,然后使用解析器将它们组合起来。例如在 HTTP header 中会有 GET
、POST
或 PUT
以及 URL
和 HTTP_VERSION
等标记。现在的问题是, URL 包含例如字符串 "POST"
和词法分析器无法区分 URL
标记中的 "POST"
或实际 POST
标记中的 "POST"
。
该问题的解决方案是使用 flex 启动条件状态,根据预期启用和禁用特定模式。在 INITIAL
状态下找到 GET
、POST
等标记后,词法分析器切换到另一个只匹配 URL
的状态。这个解决方案虽然感觉不对。感觉就像在属于解析器的词法分析器中实现逻辑(比如“正好有一个 GET
、POST
、... 标记后跟一个 URL
)。
这引出了我的问题:
有没有一种方法可以在 bison 解析器和 flex 词法分析器之间“同步”,以便我可以根据 bison 期望的下一个标记来更改词法分析器状态?
P.S.: 我不太了解语法 类 和解析语言背后的理论知识。在我看来,解析 HTTP header 甚至不需要像 bison 这样的无上下文语言解析器。 HTTP是不是正则语言,我可以用正则表达式解析?
使用 Bison 来解析 HTTP header 不仅仅是矫枉过正;这是工具和问题之间的不匹配。这就像尝试使用 Photoshop 写一篇文章。 Photoshop是一种高度复杂的工具,在熟练的操作者手中,它可以使任何图像看起来都很漂亮,从某种意义上说,一篇文章就是一个图像(或一系列图像)。但这个任务很荒谬。当然,Photoshop 有文本块。但是您不想专注于每个矩形文本块。您想书写,让文字从一页流到另一页,这是 Photoshop 模型之外的东西,无论该工具多么复杂。
Bison 和 Flex 旨在解析具有复杂语法的语言,在这种语言中,输入可以首先被分成词汇单元(标记),而不考虑它们的语法上下文。如果您发现自己在问诸如“我怎样才能将预期输入的性质传达给词法分析器?”之类的问题,那么您可能使用了错误的工具。当然,Flex 是一个强大的工具,它具有的特性使其能够适应词汇上下文中的微小变化。但这些应该是特例。
像 HTTP 这样的协议被设计成易于分析。您既不需要解析器也不需要词法分析器来查看行首是少数几个可能的动词中的哪一个,或者将以下字符串提取到第一个 space 字符。您不需要进行复杂的错误分析和恢复,您甚至不应该尝试,因为它会泄露信息并可能打开漏洞。如果一个字符无法解析,就发送一个400并停止读取。
好的工具可以简化其设计领域内问题的解决。优秀工程师的部分技能是识别哪些工具适用于给定的问题。在这种情况下,Bison/Flex 不是工具。
我也不确定正则表达式有多大帮助,因为 HTTP 解析中的主要挑战是处理间歇性、异步、有点不可靠且容易受到攻击的输入流。与 Flex 一样,大多数正则表达式库都需要一个已经明确终止的输入字符串,而通过 Internet 传输的协议则不是这种情况。
构建从 Bison 解析器到 Flex 扫描器的反向通道是可能的,但这不是尝试的地方。所以我不愿意尝试在这种情况下解释这些技术。
HTTP 是一种常规语言。从事实中我们可以看出,它可以用有限状态机来解析。理论上应该可以(不要引用我的话)用正则表达式匹配整个 HTTP 消息。这种解析方法的问题在于,常见的正则表达式语言没有复杂的捕获选项。通常我们可以捕获单个子匹配并将它们存储起来供以后使用,但是在 bison 中没有像 callback-like 方法这样的东西,在这种方法中可以根据对某些子模式的识别指定任意操作。
bison 和 flex 不是解决此问题的正确工具的原因(如其他答案中所述)在于一个非常基本的 属性,它将 HTTP 语言与典型的编程语言区分开来,其中 flex 和 bison通常使用:
编程语言由符号字母表组成。这意味着例如可以将关键字视为该字母表中的单个元素,并且可以将输入的字符流明确地转换为标记流。这正是词法分析器的目的,它充当从一个字母表到另一个字母表的翻译器。在某些情况下,词法分析器还充当解析器并且需要更多的内部逻辑,而不是简单地将输入序列转换为标记。这些情况中最常见的一种是评论。评论中的关键字不再发出标记。
另一方面,对于 HTTP,字母表只是输入字符。使用词法分析器没有多大意义。 OP 提到的关于 flex 和 bison 之间通信的问题源于这样一个事实,即他试图将语言的解析(这是一个单一的问题)分成两部分。 Flex 不是 解析器,不适合解析。解决方案是忽略词法分析器阶段,因为它不是必需的。 Bison 非常有能力为常规语言生成解析器,可用于解析 HTTP。
这让我想到了最后一点。即使 bison 能够生成常规语言解析器,它也不是最合适的工具。 Bison 可以为 context-free 种语言生成解析器。这些是使用带有堆栈的有限状态机进行解析的。对于解析一种常规语言,不需要堆栈,因为没有需要“记住”的嵌套结构。因此,bison 生成的 HTTP 解析器很可能不会像常规语言解析器生成器生成的解析器那样优化。遗憾的是,我找不到一个纯正则语言解析器生成器,但这样的东西将是生成 HTTP 解析器的首选工具。