表示语法中的语句终止换行符?

2024-02-15

许多编程语言都有以行结束符终止的语句。不过,通常情况下,如果解析器无法理解该行,则在语句中间允许使用行结束符。例如,

a = 3 +
4

...将在 Ruby 和 Python* 中解析为语句a = 3+4, since a = 3+没有任何意义。换句话说,换行符被忽略,因为它会导致解析错误。

我的问题是:如何使用分词器和解析器简单/优雅地完成相同的行为?我使用 Lemon 作为解析器生成器,如果它有什么区别的话(尽管我也将这个问题标记为 yacc 因为我确信该解决方案同样适用于这两个程序)。

我现在是这样做的:在任何不会出现语法歧义的情况下,允许有选择地出现语句终止符。换句话说,就像

expression ::= identifier PLUS identifier statement_terminator.
expression ::= identifier PLUS statement_terminator identifier statement_terminator.

...换句话说,可以在加号后面使用换行符,因为这不会对语法的歧义产生任何影响。我担心这会扩大语法的大小,并且我有很多机会错过案例或在语法中引入微妙的错误。有没有更简单的方法来做到这一点?

编辑*:实际上,该代码示例不适用于 Python。事实上,如果你传入这样的内容,Python 确实会忽略换行符:

print (1, 2,
3)

您可能可以使解析器生成器得到正确的结果,但这可能需要修改解析器生成器的骨架。

我知道三种可行的算法;没有一个是完美的。

  1. 如果出现以下情况,请在行尾插入显式语句终止符:

    A。前一个标记不是语句终止符,并且

    b.可以移动语句终止符。

  2. 在以下情况下,在不可移动标记(Ecmascript 中的“违规标记”)之前插入显式语句终止符:

    A。有问题的标记位于行的开头,或者是}或者是输入结束标记,并且

    b.移动语句终止符不会导致空语句生成量的减少。 [1]

  3. 列出所有代币对的清单。对于每个标记对,确定是否适合用语句终止符替换行结束符。您也许可以使用上述算法之一来计算此表。

算法3是最容易实现的,但也是最难计算的。而且每次修改语法时可能都需要调整表格,这会大大增加修改语法的难度。如果您可以计算标记对表,则词法分析器可以处理插入语句终止符。 (如果您的语法是运算符优先语法,那么您可以在任何没有优先关系的标记之间插入语句终止符。但是,即使这样,您也可能希望针对受限上下文进行一些调整。)

如果您可以在不破坏上下文的情况下向解析器查询标记的可移动性,则可以在解析器中实现算法 1 和 2。最近版本的 bison 允许您指定他们所谓的“LAC”(LookAhead Correction),这涉及到这样做。从概念上讲,解析器堆栈被复制并且解析器尝试处理令牌;如果令牌最终被转移(可能在一定次数的减少之后),而没有触发错误产生,则令牌是有效前瞻的一部分。我还没有查看实现,但很明显实际上没有必要复制堆栈来计算可转移性。无论如何,如果你想使用它,你必须对该设施进行逆向工程到 Lemon 中,这将是一个有趣的练习,可能不会太困难。 (您还需要修改 bison 骨架才能执行此操作,但从 LAC 实现开始可能会更容易。bison 目前仅使用 LAC 来生成更好的错误消息,但它确实涉及测试每个令牌的可转移性。)

在上述所有算法中,需要注意的一件事是可能以括号表达式开头的语句。 Ecmascript 尤其会犯这个错误(恕我直言)。 Ecmascript 示例,直接来自报告:

a = b + c
(d + e).print()

Ecmascript 会将其解析为单个语句,因为c(d + e)是语法上有效的函数调用。最后,(不是一个有问题的令牌,因为它可以被转移。不过,程序员不太可能有意这样做,并且在执行代码(如果执行的话)之前不会产生错误。

请注意,算法 1 会在第一行末尾插入一个语句终止符,但同样不会标记歧义。这更有可能是程序员的意图,但未标记的歧义仍然令人烦恼。

Lua 5.1 会将上面的示例视为错误,因为它不允许在函数对象和(在调用表达式中。然而,Lua 5.2 的行为类似于 Ecmascript。

另一个经典的歧义是return(以及可能的其他陈述)其中有一个optional表达。在 ECMAScript 中,return <expr>属于限制生产;关键字和表达式之间不允许有换行符,因此return在行尾自动插入分号。在 Lua 中,它并不含糊,因为return语句后面不能跟另一个语句。


Notes:

  1. Ecmascript 还要求将语句终止符标记解析为语句终止符,尽管它并没有完全这么说;它不允许在 a 的迭代器子句中使用分号for自动插入语句。其算法还包括在两个上下文中强制插入分号:在return/throw/continue/break出现在行尾和之前的标记++/--出现在行开头的标记。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

表示语法中的语句终止换行符? 的相关文章

  • 我应该在哪里划清词法分析器和解析器之间的界限?

    我正在为 IMAP 协议编写一个词法分析器 用于教育目的 但我很困惑应该在词法分析器和解析器之间划清界限 以 IMAP 服务器响应为例 FLAGS Answered Deleted 该响应的正式语法定义如下 mailbox data FLA
  • 能否使用 jQuery 的 $(responseXML) 语法可靠地解析 XML?

    我目前正在寻找一种使用 JavaScript 从服务器 XML 响应中提取信息的简单方法 jQuery 似乎是一个很好的候选者 当谈到使用 jQuery 解析 XML 时 我不断遇到类似于以下代码片段的代码示例 function parse
  • 编程语言解析器的来源?

    我正在清理我的一个旧项目 该项目计算有关大型软件项目的许多简单指标 指标之一是文件 类 方法的长度 目前 我的代码 猜测 类 方法边界的位置基于非常粗略的算法 遍历文件 维护 当前深度 并在遇到未加引号的括号时调整它 当您返回到类或方法开始
  • 解析嵌套括号内包含的值

    我只是在开玩笑 奇怪地发现在简单的递归函数中解析嵌套括号有点棘手 例如 如果程序的目的是查找用户详细信息 它可能来自 name surname age to Bob Builder age 然后到Bob Builder 20 这是一个用于在
  • 从 XML 构建树结构的速度很慢

    我正在将 XML 文档解析为我自己的结构 但对于大型输入来说构建它非常慢 是否有更好的方法来做到这一点 public static DomTree
  • 如何在 Linux 中使用单行命令获取 Java 版本

    我想通过单个命令获取 Linux 中的 Java 版本 我是 awk 的新手 所以我正在尝试类似的事情 java version awk print 3 但这不会返回版本 我将如何获取1 6 0 21从下面的Java版本输出 java ve
  • csv格式是常规语法还是上下文无关语法?

    我目前正在编写一个 csv 解析器 csv 格式的定义由下式给出RFC4180 https www rfc editor org rfc rfc4180这是由 ABNF 定义的 所以csv的定义绝对是上下文无关语法 不过我想知道csv是否是
  • 使用 js-xlsx 解析 Excel 工作表

    我正在尝试解析用户指定的目录中的所有 Excel 文件 但js xlsx我正在使用的库似乎需要手动导航 var url test files test xlsx lt Located in the project directory var
  • 如何在Java中有效地读取由大量小项目组成的大型XML文件?

    我有一个很大的 XML 文件 其中包含相对固定大小的项目 即
  • 用于冒号分隔标签的 XML 解析器? [关闭]

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

    我想编写一个函数 它将返回 FontStyle 并以字符串作为参数 FontStyle f function Italic FontStyles Italic 我不想编写 Switch case 或 if else 语句来执行相同的操作 对
  • 使用 R 读取和转换二进制原始数据

    我有一个file https drive google com file d 0BxMpk0nhnJy6SFhxd2xuMzJYYlk edit usp sharing其中包含原始 二进制数据和 ascii 它包含一个时间戳和一个代表速度的
  • 使用 FoldLine 解析多个块

    对于这个简化的问题 我试图解析一个如下所示的输入 foo bar baz quux woo hoo xyzzy glulx into foo bar baz quux woo hoo xyzzy glulx 我尝试过的代码如下 import
  • 如何在 Azure 逻辑应用中解析 Excel 电子表格

    我需要使用 Azure 逻辑应用从 Excel 电子表格中解析和提取列信息 我已经为我的逻辑应用程序设置了从 Outlook 检索最新未读电子邮件的功能 此外 我的逻辑应用程序执行 FOR EACH 来读取所有附件 来自未读电子邮件 并确保
  • Java 库有 parseInt、parseLong、parseDouble 等接受默认值并且不抛出异常吗?

    我喜欢中的建议java中的String到Int 可能是坏数据 需要避免异常 https stackoverflow com questions 174502 string to int in java likely bad data nee
  • 位图内存不足错误

    我对这个错误有疑问 我从 URL 制作网站图标解析器 我这样做是这样的 public class GrabIconsFromWebPage public static String replaceUrl String url StringB
  • 需要使用 pyparsing 制作递归解析器的帮助

    我正在尝试使用 python pyparsing 进行解析 我在制作递归解析器时陷入困境 让我解释一下问题 我想要计算元素的笛卡尔积 语法是 cross elements element 我用更具体的方式 cross a c1 or cro
  • LL(1) 解析器中 FIRST 和 FOLLOW 集的用途?

    谁能向我解释一下 LL 1 语法中如何使用 FIRST 和 FOLLOW 我知道它们用于语法表构建 但我不明白如何使用 在 LL 1 解析器中 解析器的工作方式是维护一个工作空间 该工作空间最初播种到开始符号 后跟字符串结束标记 通常表示为
  • C# 是否有像 Java 那样的字符串分词器?

    我正在做简单的字符串输入解析 我需要一个字符串标记器 我是 C 新手 但已经编写过 Java 程序 因此 C 应该有一个字符串标记生成器似乎很自然 可以 它在哪里 我该如何使用它 你可以使用String Split 方法 http msdn
  • 有没有办法改变野牛的弹性启动状态?

    我在词法分析器中定义了不同的状态 这些状态的变化不取决于令牌 而是取决于令牌序列 类似于模板引擎的工作方式 我可以定义更长的标记 但我更喜欢这种方法 您可以将一个函数粘贴到使用 BEGIN 宏的 l 文件的第三部分中 然后从您的 bison

随机推荐