ANTLR4的类似Python的缩进标记

antlr-denter的Python项目详细描述


类Python标记的缩进

antlrv4中INDENT/DEDENT令牌的一个基本现成的解决方案。只要插上DenterHelper就可以走了!关于这个项目背后的一些动机,请参见this blog post。在

antlr helper是在the MIT license下发布的,这基本上意味着你可以用它做任何你想做的事情。也就是说,如果你觉得这个项目有用的话,我会非常感谢你的来信!也许能成为这个项目的明星?在

用法(Java)

马文

<dependency>
  <groupId>com.yuvalshavit</groupId>
  <artifactId>antlr-denter</artifactId>
  <version>1.1</version>
</dependency>

向lexer添加INDENT/DEDENT标记

  1. 在语法中定义缩进和删除标记
  2. @lexer::members部分中,实例化一个DenterHelper,其pullToken方法委托给lexer的super.nextToken()
  3. 重写lexer的super.nextToken方法以使用DenterHelper::nextToken。在
  4. 修改您的NL标记以获取后面的任何空白(换句话说,让它以' '*'\t'*或类似的结尾)。在

DenterHelper是一个抽象类,它的构造函数也有三个参数:newline、INDENT和DEDENT的标记类型。将它实例化为匿名类可能是最容易的。整个事情应该是这样的:

^{pr2}$

Java builder 8也特别有用:

tokens { INDENT, DEDENT }

@lexer::header {
  import com.yuvalshavit.antlr4.DenterHelper;
}

@lexer::members {
  private final DenterHelper denter = DenterHelper.builder()
    .nl(NL)
    .indent(MyCoolParser.INDENT)
    .dedent(MyCoolParser.DEDENT)
    .pullToken(MyCoolLexer.super::nextToken);

  @Override
  public Token nextToken() {
    return denter.nextToken();
  }
}

NL: ('\r'? '\n' ' '*);

用法(Python3)

tokens { INDENT, DEDENT }

@lexer::header{
from DenterHelper import DenterHelper
from MyCoolParser import MyCoolParser
}
@lexer::members {
class MyCoolDenter(DenterHelper):
    def __init__(self, lexer, nl_token, indent_token, dedent_token, ignore_eof):
        super().__init__(nl_token, indent_token, dedent_token, ignore_eof)
        self.lexer: MyCoolLexer = lexer

    def pull_token(self):
        return super(MyCoolLexer, self.lexer).nextToken()

denter = None

def nextToken(self):
    if not self.denter:
        self.denter = self.MyCoolDenter(self, self.NL, MyCoolParser.INDENT, MyCoolParser.DEDENT, ***Should Ignore EOF***)
    return self.denter.next_token()

}

在解析器中使用标记

基本上,只要使用它们。有一点值得注意的是,当denter注入DEDENT标记时,它将用一个NL作为前缀。如果没有要插入的DEDENTs,则在EOF标记之前还插入一个NL。例如,给定以下输入:

hello
  world
    universe
dolly

。。。代币大概是:

"hello"
INDENT
"world"
INDENT
"universe"
NL
DEDENT
DEDENT
"dolly"
NL
<eof>

这样做是为了使简单表达式可以由NL标记终止,而不必担心周围的上下文(即将发生的dedent或EOF)。在本例中,universe和{}表示简单的表达式,您可以想象语法包含类似statement: expr NL | helloBlock;的内容。别紧张!在

“半个树根”

当你放弃一个从未建立的缩进水平时会发生什么?在

someStatement()
if foo():
    if bar():
      fooAndBar()
  bogusLine()

请注意,bogusLine()与任何缩进级别都不匹配:它比if foo()缩进得多,但比它的第一个语句if bar()少。在

这是python中的一个有缺陷的程序。如果你运行这样一个程序,你会得到:

IndentationError: unindent does not match any outer indentation level

DenterHelper处理器通过插入两个令牌来处理这一问题:一个DEDENT紧跟着一个INDENT(这里的总序列实际上是两个DEDENT,后面跟着一个INDENT,因为bogusLine()是从fooAndBar()中提取两次的)。其基本原理是该行已向其父行倾斜,然后缩进。它与缩进标记一致,例如:

someStatement()
  bogusLine()

如果您的缩进方案与python类似,那么您很可能希望这是一个编译错误。好消息是,只要解析器不允许“自发”缩进。也就是说,如果这一段前面的例子失败了,那么上面的半个例子也会失败。在这两种情况下,解析器规则都会遇到意外的INDENT标记。在

回购布局

  • ^{str1}$Java/core:真实的东西。这就是你感兴趣的。Maven工件antlr-denter。在
  • Java/examples:包含一个使用DenterHelper的语言的真实示例,因此您可以看到完整的解决方案,包括pom、如何设置解析器(与通常的antlr内容相比没有什么额外的内容)以及如何定义使用这些INDENT/DEDENT标记的语言。语言本身是相当基础的,但它应该能让人理解。Maven工件antlr-denter-example-examples。在
  • Python3:Python3实现

maven运行就像mvn install(或您最喜欢的目标)一样简单。在

评论?建议?漏洞?在

不要羞于打开一个i嘘!在

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
JFrame中的Java多线程   java Servlet异常映射   java无法从输出流读取   swing Java带来的小程序GUI问题   java什么原因导致错误“'void'类型此处不允许”以及如何修复它?   Java选择器select(长)与selectNow的区别   java自定义arraylist<mygames>获得不同   java Icepdf注释让页面消失   java反向整数数组   java I在生成同步“无法解析配置的所有依赖项”时遇到此错误:app:debugRuntimeClasspath   多个虚拟机上的java线程访问单个DB实例上的表,有时会导致性能低下和异常   swing更改Java中的默认按钮,使其看起来“更好”   java慢速MQ主题订阅。并行化不能提高性能   java运行Boggle Solver需要一个多小时。我的代码怎么了?   数据库中的java循环与应用程序中的java循环   正则表达式匹配${123…456}并在Java中提取2个数字?   java如何制作我们软件的试用版   Java内存参数计算   从另一个类调用方法时出现java问题