2009-10-10 23 views
9

Đâ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 INDENTDEDENT 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

Trả lời

10

Có một vài ví dụ trên pyparsing wiki Examples page mà có thể cung cấp cho bạn một số hiểu biết:

Để sử dụng pyparsing của indentedBlock, tôi nghĩ rằng bạn sẽ xác định suite như:

indentstack = [1] 
suite = indentedBlock(stmt, indentstack, True) 

Lưu ý rằng indentedGrammarExample.py trước ngày sự bao gồm của indentedBlock trong pyparsing, thì implemention riêng của mình phân tích cú pháp thụt lề.

Các vấn đề liên quan