[英]ANTLR4 Python parsing big files
我正在嘗試為 juniper/srx 路由器訪問控制列表編寫解析器。 以下是我正在使用的語法:
grammar SRXBackend;
acl:
'security' '{' 'policies' '{' COMMENT* replaceStmt '{' policy* '}' '}' '}'
applications
addressBook
;
replaceStmt:
'replace:' IDENT
| 'replace:' 'from-zone' IDENT 'to-zone' IDENT
;
policy:
'policy' IDENT '{' 'match' '{' fromStmt* '}' 'then' (action | '{' action+ '}') '}'
;
fromStmt:
'source-address' addrBlock # sourceAddrStmt
| 'destination-address' addrBlock # destinationAddrStmt
| 'application' (srxName ';' | '[' srxName+ ']') # applicationBlock
;
action:
'permit' ';'
| 'deny' ';'
| 'log { session-close; }'
;
addrBlock:
'[' srxName+ ']'
| srxName ';'
;
applications:
'applications' '{' application* '}'
| 'applications' '{' 'apply-groups' IDENT ';' '}' 'groups' '{' replaceStmt '{' 'applications' '{' application* '}' '}' '}'
;
addressBook:
'security' '{' 'address-book' '{' replaceStmt '{' addrEntry* '}' '}' '}'
| 'groups' '{' replaceStmt '{' 'security' '{' 'address-book' '{' IDENT '{' addrEntry* '}' '}' '}' '}' '}' 'security' '{' 'apply-groups' IDENT ';' '}'
;
application:
'replace:'? 'application' srxName '{' applicationStmt+ '}'
;
applicationStmt:
'protocol' srxName ';' #applicationProtocol
| 'source-port' portRange ';' #applicationSrcPort
| 'destination-port' portRange ';' #applicationDstPort
;
portRange:
NUMBER #portRangeOne
| NUMBER '-' NUMBER #portRangeMinMax
;
addrEntry:
'address-set' IDENT '{' addrEntryStmt+ '}' #addrEntrySet
| 'address' srxName cidr ';' #addrEntrySingle
;
addrEntryStmt:
('address-set' | 'address') srxName ';'
;
cidr:
NUMBER '.' NUMBER '.' NUMBER '.' NUMBER ('/' NUMBER)?
;
srxName:
NUMBER
| IDENT
| cidr
;
COMMENT : '/*' .*? '*/' ;
NUMBER : [0-9]+ ;
IDENT : [a-zA-Z][a-zA-Z0-9,\-_:\./]* ;
WS : [ \t\n]+ -> skip ;
當我嘗試使用約 80,000 行的 ACL 時,生成解析樹最多需要約 10 分鍾。 我正在使用以下代碼來創建解析樹:
from antlr4 import *
from SRXBackendLexer import SRXBackendLexer
from SRXBackendParser import SRXBackendParser
import sys
def main(argv):
ipt = FileStream(argv[1])
lexer = SRXBackendLexer(ipt)
stream = CommonTokenStream(lexer)
parser = SRXBackendParser(stream)
parser.acl()
if __name__ == '__main__':
main(sys.argv)
我使用 Python 2.7 作為目標語言。 我還運行了 cProfile 以確定哪個代碼花費的時間最多。 以下是按時間排序的前幾條記錄:
ncalls tottime percall cumtime percall filename:lineno(function)
608448 62.699 0.000 272.359 0.000 LexerATNSimulator.py:152(execATN)
5007036 41.253 0.000 71.458 0.000 LexerATNSimulator.py:570(consume)
5615722 32.048 0.000 70.416 0.000 DFAState.py:131(__eq__)
11230968 24.709 0.000 24.709 0.000 InputStream.py:73(LA)
5006814 21.881 0.000 31.058 0.000 LexerATNSimulator.py:486(captureSimState)
5007274 20.497 0.000 29.349 0.000 ATNConfigSet.py:160(__eq__)
10191162 18.313 0.000 18.313 0.000 {isinstance}
10019610 16.588 0.000 16.588 0.000 {ord}
5615484 13.331 0.000 13.331 0.000 LexerATNSimulator.py:221(getExistingTargetState)
6832160 12.651 0.000 12.651 0.000 InputStream.py:52(index)
5007036 10.593 0.000 10.593 0.000 InputStream.py:67(consume)
449433 9.442 0.000 319.463 0.001 Lexer.py:125(nextToken)
1 8.834 8.834 16.930 16.930 InputStream.py:47(_loadString)
608448 8.220 0.000 285.163 0.000 LexerATNSimulator.py:108(match)
1510237 6.841 0.000 10.895 0.000 CommonTokenStream.py:84(LT)
449432 6.044 0.000 363.766 0.001 Parser.py:344(consume)
449433 5.801 0.000 9.933 0.000 Token.py:105(__init__)
除了 InputStream.LA 需要大約半分鍾之外,我真的無法理解它。 我想這是因為整個文本字符串被立即緩沖/加載。 是否有任何替代/更懶惰的方法來解析或加載 Python 目標的數據? 我可以對語法進行任何改進以加快解析速度嗎?
謝謝
我的理解是,由於*
而不是+
,您的IDENT
可以為零。 這會將解析器發送到每個字符的循環中,從而生成零大小的IDENT
節點。
試試這個:
# Install ANTLR and the Python runtime for ANTLR
!pip install antlr4-python3-runtime
# Generate a parser from the grammar
!antlr4 -Dlanguage=Python SRXBackend.g4
# Import the generated parser and lexer
from SRXBackendParser import SRXBackendParser
from SRXBackendLexer import SRXBackendLexer
# Read the input file
with open("input.txt", "r") as file:
input_str = file.read()
# Create a lexer and parser
lexer = SRXBackendLexer(InputStream(input_str))
stream = CommonTokenStream(lexer)
parser = SRXBackendParser(stream)
# Parse the input
tree = parser.acl()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.