Antlr4 在树莓派上速度慢

3
我们正在尝试在树莓派B上使用Antlr4(Python2目标)解析自定义语言。然而,它太慢了,无法进行任何严肃的操作:解析几行需要大约十秒钟。这是我的代码:
Transposeur.py:
# -*- coding:Utf-8 -*-

from antlr4 import *
from TransposeurLexer import TransposeurLexer
from TransposeurParser import TransposeurParser
import sys
from Listener import Listener

def transpose(file_path):

  input = FileStream(file_path)
  lexer = TransposeurLexer(input)
  stream = CommonTokenStream(lexer)
  parser = TransposeurParser(stream)
  tree = parser.myfile()
  listener = Listener()
  walker = ParseTreeWalker()
  walker.walk(listener, tree)
  return listener.array

Transposeur.g4:

grammar Transposeur;

myfile: block+;

block: title
     | paragraph
     ;

title: firstTitle
     | secondTitle
    ;

firstTitle: '#' ' '? unit+ newline;
secondTitle: '##' ' '? unit+ newline;

paragraph: unit+ newline;

unit: low+
    | upper
    | (low | cap)* cap (low | cap)*
    | ponctuation
    | number
    | space
    ;

upper: cap cap+;
number: digit+;

low: LOW;
cap: CAP;
newline: NEWLINE;
ponctuation: SPACE? PONCT;
space: SPACE;
digit: DIGIT;

LOW: [a-z] | 'ç' | 'é' | 'è' | 'à' | 'â' | 'ê' | 'ù' | 'î' | 'ô' | 'û' | 'ë' | 'ï' | 'ü' | 'œ';
CAP: [A-Z];
NEWLINE: '\r'? '\n';
SPACE: ' ';
DIGIT: [0-9];
PONCT: ',' | '!' | '?' | ';' | '.' | ':';

需要花费时间的命令是 tree = parser.myfile()。有没有办法让它更快?


ANTLR在解析方面非常出色。即使在“慢”机器上,几行代码也不算什么。这在其他CPU上是否更“快”?你要输入的文本到底是什么? - Ira Baxter
对称地,你写成了“low+”,那么为什么不把“upper”简单地写成“cap+”呢? - Ira Baxter
因为大写字母至少应该有两个。在我的笔记本电脑上,同样的事情只需要不到一秒钟就可以运行完成。 - user1361491
1个回答

5

我怀疑问题出在它无法解析low+ vs (low | cap)* .... 这种情况上,它可能需要向前任意查找以确定应用哪个规则。

我认为真正的问题在于你的unit+参考对于low+来说存在歧义。给定一个由以下内容组成的单位文本:

      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

(五十个"a"字符). 可以通过以下方式解析:

  • 一个具有所有"a"的low+级别的单元
  • 单元单元,第一个是任何前缀的low+,第二个是其余"a"的low+(这有2500种可能性)
  • 单元单元单元,第一个是任何前缀的low+,最后一个是任何剩余后缀的low+,中间是介于两者之间的字符(可能性更多)
  • 单元单元单元单元...

所以我认为您的语法在这部分非常模糊,ANTLR正在探索巨大的选择空间,试图选择其中一个。您可能很幸运,ANTLR足够快以完成整个过程:-}

您将遇到与unit+upper(== cap+)相同的问题。

对我来说,您真正需要捕获的单元结构有多少并不清楚。看起来您只需要一个字符串。尝试重新编码它如下:

unit: low
    | cap
    | ponctuation
    | number
    | space
  ; 

更好的做法是这样定义单元:
unit: LOW | CAP | PONCT | DIGIT | SPACE ;

嗨,感谢您的回答。所有这些单元都需要在侦听器中拥有自己的规则。我还需要区分大小写字母和混合字。而且,一个单独的大写字母单词('A')被视为混合字。 - user1361491
1
使用“纯粹”的ANTLR语法规则只会让你陷入歧义的困境。因此,要么改变你使用ANTLR规则的方式(我建议考虑一种语义动作,使特定类型的单元在另一个单元识别字符串时放弃),要么将单元识别推入词法分析器中,假设词法匹配具有某种贪婪属性,并且将寻找最长匹配项。这就是我的ANTLR4知识的局限性所在;我不太清楚你可以为词法标记编写什么,或者ANTLR是否有某种贪婪规则。大多数生成的词法分析器都有这样的规则。 - Ira Baxter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接