ANTLR 词法分析器如何消除其规则的歧义(或者为什么我的解析器会产生“输入不匹配”错误)?

2023-11-29

Note:这是一个自答问题旨在为 ANTLR 用户最常犯的错误之一提供参考。


当我测试这个非常简单的语法时:

grammar KeyValues;

keyValueList: keyValue*;
keyValue: key=IDENTIFIER '=' value=INTEGER ';';

IDENTIFIER: [A-Za-z0-9]+;
INTEGER: [0-9]+;

WS: [ \t\r\n]+ -> skip;

输入以下内容:

foo = 42;

我最终遇到以下运行时错误:

第 1:6 行不匹配输入“42”,需要 INTEGER
第 1:8 行输入“​​;”不匹配期待“=”

为什么ANTLR不识别42 as an INTEGER在这种情况下?
它应该与模式匹配[0-9]+正好。

如果我颠倒顺序INTEGER and IDENTIFIER定义它似乎有效,但为什么顺序首先很重要?


在ANTLR中,词法分析器与解析器是隔离的,这意味着它将把文本分割成typed根据词法分析器语法规则进行标记,解析器对此过程没有影响(不能说“给我一个INTEGER now"例如)。它产生一个令牌流通过它自己。此外,解析器不关心标记文本,它只关心标记类型以匹配其规则。

当多个词法分析器规则可以匹配相同的输入文本时,这很容易成为问题。在这种情况下,将根据这些选择令牌类型优先规则:

  • 首先,选择与longest输入子串
  • 如果最长匹配的子字符串等于隐式定义的标记(例如'='),使用隐式规则作为token类型
  • 如果多个词法分析器规则匹配相同的输入,请选择first一、基于定义顺序

为了有效地使用 ANTLR,记住这些规则非常重要。


在问题的示例中,解析器期望看到以下标记流来匹配keyValue解析器规则:IDENTIFIER '=' INTEGER ';' where '=' and ';'是隐式标记类型。

Since 42可以匹配both INTEGER and IDENTIFIER, and IDENTIFIER首先定义,解析器将收到以下输入:IDENTIFIER '=' IDENTIFIER ';'它将无法匹配到keyValue规则。请记住,解析器cannot交流to词法分析器,它只能从中接收数据,因此它不能说“尝试匹配INTEGER next".

建议尽量减少词法分析器规则重叠,以限制此效果的影响。在上面的例子中,我们有几种选择:

  • 重新定义IDENTIFIER as [A-Za-z] [A-Za-z0-9]*(要求以字母开头)。这完全避免了这个问题,但阻止了定义以数字开头的标识符名称,因此它改变了语法的意图。
  • Reorder INTEGER and IDENTIFIER。这解决了大多数情况下的问题,但阻止了定义完全数字的标识符,因此它也以微妙的、不那么明显的方式改变了语法的意图。
  • 当词法分析器规则重叠时,使解析器接受两种标记类型:
    首先,交换INTEGER and IDENTIFIER为了优先考虑INTEGER。然后,定义解析器规则id: IDENTIFIER | INTEGER;然后使用该规则而不是IDENTIFIER在其他解析器规则中,这会改变keyValue to key=id '=' value=INTEGER ';'.

这是要总结的第二个词法分析器行为示例:

组合语法如下:

grammar LexerPriorityRulesExample;

// Parser rules

randomParserRule: 'foo'; // Implicitly declared token type

// Lexer rules

BAR: 'bar';
IDENTIFIER: [A-Za-z]+;
BAZ: 'baz';

WS: [ \t\r\n]+ -> skip;

给定以下输入:

aaa foo bar baz barz

将从词法分析器生成以下标记序列:

IDENTIFIER 'foo' BAR IDENTIFIER IDENTIFIER EOF

  • aaa属于类型IDENTIFIER

    只有IDENTIFIER规则可以匹配这个标记,没有歧义。

  • foo属于类型'foo'

    解析器规则randomParserRule引入了隐含的'foo'令牌类型,优先于IDENTIFIER rule.

  • bar属于类型BAR

    这段文字匹配BAR规则,其定义为before the IDENTIFIER规则,因此具有优先权。

  • baz属于类型IDENTIFIER

    这段文字匹配BAZ规则,但它也符合IDENTIFIER规则。后者是根据定义选择的before BAR.

    考虑到语法,BAZ永远无法匹配,因为IDENTIFIER规则已经涵盖了一切BAZ可以匹配。

  • barz属于类型IDENTIFIER

    The BAR规则可以匹配该字符串的前 3 个字符 (bar),但是IDENTIFIER规则将匹配 4 个字符。作为IDENTIFIER匹配更长的子串,它被选择BAR.

  • EOF (文件结尾) 是隐式定义的标记类型,始终出现在输入的末尾。

根据经验,应定义具体规则before更通用的规则。如果规则只能匹配先前定义的规则已覆盖的输入,则它将never使用。

隐式定义的规则,例如'foo'就好像它们已被定义一样before所有其他词法分析器规则。由于它们增加了复杂性,建议完全避免它们并声明显式词法分析器规则。这种方法的一个显着优点是,只需将标记列表放在一个位置,而不是将它们分散在语法中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ANTLR 词法分析器如何消除其规则的歧义(或者为什么我的解析器会产生“输入不匹配”错误)? 的相关文章

  • VBA:访问 JSON

    我正在处理 VBA 投影 但不确定如何访问此 JSON 中的 id 应该将 players 设置为什么才能在循环中获取 id 我已经用更多代码更新了问题 JSON event games players id 182759 Code Pri
  • 自动解析 PHP,将 PHP 代码与 HTML 分离

    我正在开发一个大型 PHP 代码库 我想将 PHP 代码与 HTML 和 JavaScript 分开 我需要对 PHP 代码进行多次自动搜索和替换 对 HTML 进行不同的搜索和替换 对 JS 进行不同的自动搜索和替换 有没有一个好的解析器
  • 如何使用 SAX Java 解析器读取注释文本

    我只想使用 Java 中的 SAX 解析器读取 XML 文件中对象标记的注释 这是我的文件的摘要
  • java数据结构模拟数据树

    我需要帮助定义使用什么方法 我有一个 SOAP 响应 给我一个 xml 文件 我需要在屏幕上显示 3 个相关列表 当您在第一个列表中选择一个项目时 相应的选择将出现在第二个列表中 依此类推 我只对从 xml 流中提取数据后如何有效地组织数据
  • 用于冒号分隔标签的 XML 解析器? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 从字符串名称返回 FontStyle

    我想编写一个函数 它将返回 FontStyle 并以字符串作为参数 FontStyle f function Italic FontStyles Italic 我不想编写 Switch case 或 if else 语句来执行相同的操作 对
  • 使用 FoldLine 解析多个块

    对于这个简化的问题 我试图解析一个如下所示的输入 foo bar baz quux woo hoo xyzzy glulx into foo bar baz quux woo hoo xyzzy glulx 我尝试过的代码如下 import
  • 用 C++ 生成 AST

    我正在用 C 制作一个解释器 到目前为止我已经有了词法分析器来生成标记 问题是我不确定如何生成 行走 解析树 我正在考虑使用数组数组来制作解析树 但我不确定如何以正确的顺序将标记实际插入到解析树中 我不确定是自上而下 左右还是自下而上 左右
  • 用于(联合国)结构化文本文档的词法分析器/解析器[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有很多脚本解析器和词法分析器 即结构化计算机语言 但我正在寻找一个可以将 几乎 非结构化文本文档分成更
  • 如何使用 BeautifulSoup 从表中选择特定行?

    So I have a question related to a previous question but I realized I needed to go one level more to get an 11 digit NDC
  • 获取 Parse Analytics 自定义仪表板

    是否可以使用 Javascript 或 REST API 从 Parse 获取应用程序分析 我想在我自己的仪表板中显示下载数量和自定义事件 不可以 您只能通过 REST API 推送 https parse com docs rest ht
  • 位图内存不足错误

    我对这个错误有疑问 我从 URL 制作网站图标解析器 我这样做是这样的 public class GrabIconsFromWebPage public static String replaceUrl String url StringB
  • SQL Server OPENJSON读取嵌套json

    我有一些想要在 SQL Server 2016 中解析的 json 有一个项目 gt 结构 gt 属性的层次结构 我想编写一个解析整个层次结构的查询 但我不想通过索引号指定任何元素 即我不想做这样的事情 openjson json 0 or
  • 使用 ANTLR 为 java 源代码生成抽象语法树

    如何使用 ANTLR 从 java src 代码生成 AST 有什么帮助吗 好的 步骤如下 前往ANTLR站点 http www antlr org 并下载最新版本 下载Java g和JavaTreeParser g文件来自here htt
  • 使用 ANTLR 验证 LL(1) 语法

    我知道 ANTLR 可以接受 LL 语法 但是 有什么方法可以使用 ANTLR 检查语法是否是 LL 1 吗 options k 1 如果你的语法不在 LL 1 中 它会发出警告
  • LL(1) 解析器中 FIRST 和 FOLLOW 集的用途?

    谁能向我解释一下 LL 1 语法中如何使用 FIRST 和 FOLLOW 我知道它们用于语法表构建 但我不明白如何使用 在 LL 1 解析器中 解析器的工作方式是维护一个工作空间 该工作空间最初播种到开始符号 后跟字符串结束标记 通常表示为
  • _实际_ Twitter 主题标签格式?不是你的正则表达式,也不是他的代码——真正的代码?

    更新 如果可以的话 请使用 Twitter 的实体 他们为您以及其他项目找到了解决方案 我的情况是 我只有没有实体的推文和所有额外的元数据 我花了我认为不合理的时间试图找到actual主题标签的格式 据我搜索得知 Twitter 尚未发布任
  • 用于解析差异的 PHP 类

    我正在编写一个 PHP 脚本 需要解释 Git 创建的 Diff 文件 如果我想解析 Diff 文件并基本上以完全不同的格式打印它 我应该如何进行 我遇到过Text DiffPEAR 库 但该库仅创建 Diff 本身 或者更确切地说 它只需
  • h264 参考帧

    我正在寻找一种在 h264 流中查找参考帧的算法 我在不同的解决方案中看到的最常见的方法是查找访问单元分隔符和 IDR 类型的 NAL 不幸的是 我检查的大多数流没有 IDR 类型的 NAL 我将不胜感激的帮助 问候 雅采克 H264 帧由
  • 使用 isdigit 表示浮点数?

    a raw input How much is 1 share in that company while not a isdigit print You need to write a number n a raw input How m

随机推荐

  • Mongo 聚合与 Java for 循环和性能

    我存储了以下 mongo 文档 Field1 ABC Field2 Field3 ABC1 Field4 id 123 id 234 id 345 Field3 ABC2 Field4 id 123 id 234 id 345 Field3
  • 通过重命名旧表然后填充新版本来将表停机时间降至最低?

    我有一些左右的永久桌子需要每晚重建 为了使这些表尽可能长时间地 活动 并且也提供仅备份前一天数据的可能性 另一位开发人员含糊地建议 当夜间构建发生时 采取与此类似的路线 创建永久表 构建版本 例如 tbl build Client 重命名活
  • MYSQL 中的批量插入

    在 MS SQL 上 我可以使用下面的 sql 命令进行批量插入 BULK INSERT myDatabase MyTable FROM C MyTextFile txt WITH FIELDTERMINATOR 现在我想在 MySQL 上
  • 如何计算JavaScript中的图像加载/渲染时间?

    有没有办法使用 javascript jquery 查找网页中的图像加载 渲染时间 这里正确的答案是使用 Chrome 或 Firefox Firebug 等浏览器内置的开发工具 它会告诉您页面中所有资源的加载时间 这些工具可以访问纯 Ja
  • PHP - 遍历文件夹并显示 HTML 内容

    我目前正在尝试开发一种方法来概述我多年来创建和 合法 下载的所有不同的网页模板 我想过像这样展示它们WordPress正在使用一个小的预览窗口预览其模板 显示带有样式和所有内容的具体文件 如何将它们分为行和列并创建Ajax模式窗口在预览和分
  • 提高远程桌面上的 WPF 应用程序速度?

    在我们的场景中 我们有一个wpf应用程序 供用户通过远程桌面使用 我们发现用户体验非常慢 对于改善这种情况下的用户体验有什么建议吗 其中一点可能是禁用任何动画 故事板 并避免在 UI 中使用渐变 更多想法值得赞赏 对于渐变来说 这不像多个渲
  • unix 中正则表达式的语法错误

    我尝试找到一个与 1 到 999 之间的任何数字匹配的正则表达式 当使用钩子时我收到语法错误 bash syntax error near unexpected token 当我不使用钩子时 什么也不会发生 我的正则表达式是 egrep 1
  • Android 操作栏:我可以替换 appcompat v7 中的自定义标题吗

    我想在肌动蛋白条的左侧添加自定义操作标题 替换为默认标题 如下图所示 显示默认图像 在这里我想添加这个标题 您需要更改操作栏中的徽标和标题 您可以使用 getActivity getActionBar setTitle your title
  • Perl:如何使所需脚本中的变量在所需脚本中可用

    example out pl my our local global whatever var test require inside pm 里面 pm print var 我不想使用软件包 它超出了我的需求 谢谢 You are alwa
  • 对数组进行排序所需的最少操作数

    我正在尝试练习解决 Codeforces 中的问题 它通过将数组的元素移动到数组的开头或结尾来对数组进行排序 起初我认为它是最长的递增子序列 但在某些情况下它不起作用 例如 如果输入是 4 1 2 5 3 则 LIS 是 3 但问题的答案是
  • 如何在 C#.NET 中更改图像的像素颜色

    我正在Java中处理图像 我设计了超过100多个图像 png 格式 它们都是透明和黑色绘图 问题是 现在我被要求更改绘图的颜色 黑色 我在谷歌上搜索了许多代码 这些代码改变了图像的位图 像素 但我不猜测我必须做什么来匹配确切的像素 并在图像
  • 构建战争时删除插件视图(gsp)

    我们在 grails 应用程序中使用各种插件 如日志记录 spring security core ui acl 等 现在这些插件带有默认的 gsp 在每个插件的视图文件夹中 我想构建一个 WAR 而不包含任何插件的视图 因此 当战争现在构
  • ASP.NET 中的多选下拉列表

    asp net 是否存在任何好的带有复选框 webcontrol 的多选下拉列表 多谢 你可以使用System Web UI WebControls CheckBoxList控制或使用System Web UI WebControls Li
  • android 棒棒糖通知背景颜色

    是否可以更改 android lollipop 中通知的背景颜色 我注意到有些通知是白色的 有些是浅灰色的 有些是深灰色的 source gottabemobile com source sftcdn net 您可以看到音乐播放器通知具有深
  • 如何使用PyTorch计算偏导数?

    我想使用 PyTorch 获取输出和输入之间的偏导数 假设我有一个函数Y 5 x1 4 3 x2 3 7 x1 2 9 x2 5 然后我训练一个网络来替换这个函数 然后我使用 autograd 来计算dYdx1 dYdx2 net torc
  • 将 pandas 数据框中的所有行除以特定行

    我有一个 pandas 数据框 如下所示 Sample name C14 Cer mean C16 Cer mean C18 Cer mean C18 1 Cer mean 0 1 1 0 124749 0 285659 35 302029
  • EC2 启动时自动启动 docker-compose

    我有一个 Linux AMI 2 AWS 实例 其中包含一些通过 docker compose 编排的服务 并且我使用 docker compose up 或 docker compose start 命令来启动它们 现在我每天都会自动启动
  • 通过 ssh 包装命令:如何管理复杂的引号?

    我使用 HPC 集群 计算节点无法访问互联网 只能访问前端 所以我想包装所有需要访问互联网的命令 以便在正面执行它们 例如 对于 wget bin bash ssh frontal bin wget gt 工作正常 我必须包装这个 bq g
  • 生成所有可能的深度为 N 的树?

    我有几种不同类型的树节点 每个节点可能有 0 到 5 个子节点 我正在尝试找出一种算法来生成所有可能的深度 Here s a Python program I wrote up that I think does what you re a
  • ANTLR 词法分析器如何消除其规则的歧义(或者为什么我的解析器会产生“输入不匹配”错误)?

    Note 这是一个自答问题旨在为 ANTLR 用户最常犯的错误之一提供参考 当我测试这个非常简单的语法时 grammar KeyValues keyValueList keyValue keyValue key IDENTIFIER val