Đây là một tập hợp con của ngữ pháp Python:Làm cách nào để phân tích cú pháp indents và dedents bằng pyparsing?
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: pass_stmt
pass_stmt: 'pass'
compound_stmt: if_stmt
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
(Bạn có thể đọc toàn bộ ngữ pháp trong kho Python SVN: http://svn.python.org/.../Grammar)
Tôi cố gắng để sử dụng ngữ pháp này để tạo ra một phân tích cú pháp cho Python , bằng Python. Điều tôi đang gặp phải là làm thế nào để biểu thị các mã thông báo INDENT
và DEDENT
như các đối tượng pyparsing.
Dưới đây là cách tôi đã thực hiện các thiết bị đầu cuối khác:
import pyparsing as p
string_start = (p.Literal('"""') | "'''" | '"' | "'")
string_token = ('\\' + p.CharsNotIn("",exact=1) | p.CharsNotIn('\\',exact=1))
string_end = p.matchPreviousExpr(string_start)
terminals = {
'NEWLINE': p.Literal('\n').setWhitespaceChars(' \t')
.setName('NEWLINE').setParseAction(terminal_action('NEWLINE')),
'ENDMARKER': p.stringEnd.copy().setWhitespaceChars(' \t')
.setName('ENDMARKER').setParseAction(terminal_action('ENDMARKER')),
'NAME': (p.Word(p.alphas + "_", p.alphanums + "_", asKeyword=True))
.setName('NAME').setParseAction(terminal_action('NAME')),
'NUMBER': p.Combine(
p.Word(p.nums) + p.CaselessLiteral("l") |
(p.Word(p.nums) + p.Optional("." + p.Optional(p.Word(p.nums))) | "." + p.Word(p.nums)) +
p.Optional(p.CaselessLiteral("e") + p.Optional(p.Literal("+") | "-") + p.Word(p.nums)) +
p.Optional(p.CaselessLiteral("j"))
).setName('NUMBER').setParseAction(terminal_action('NUMBER')),
'STRING': p.Combine(
p.Optional(p.CaselessLiteral('u')) +
p.Optional(p.CaselessLiteral('r')) +
string_start + p.ZeroOrMore(~string_end + string_token) + string_end
).setName('STRING').setParseAction(terminal_action('STRING')),
# I can't find a good way of parsing indents/dedents.
# The Grammar just has the tokens NEWLINE, INDENT and DEDENT scattered accross the rules.
# A single NEWLINE would be translated to NEWLINE + PEER (from pyparsing.indentedBlock()), unless followed by INDENT or DEDENT
# That NEWLINE and IN/DEDENT could be spit across rule boundaries. (see the 'suite' rule)
'INDENT': (p.LineStart() + p.Optional(p.Word(' '))).setName('INDENT'),
'DEDENT': (p.LineStart() + p.Optional(p.Word(' '))).setName('DEDENT')
}
terminal_action
là một hàm trả về các hành động phân tích cú pháp tương ứng, tùy thuộc vào đối số của nó.
Tôi biết chức năng trợ giúp pyparsing.indentedBlock
, nhưng tôi không thể tìm ra cách áp dụng điều đó cho ngữ pháp mà không có mã thông báo PEER
.
(Nhìn vào pyparsing souce code để xem những gì tôi đang nói về)
Bạn có thể xem mã nguồn đầy đủ của tôi ở đây: http://pastebin.ca/1609860