2009-10-10 4 views
9

Tutaj jest podzbiorem gramatyki Pythona:Jak analizować wcięcia i odinięcia z pyparstwem?

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 

(Możesz przeczytać pełną gramatyki w repozytorium Python SVN: http://svn.python.org/.../Grammar)

Staram się korzystać z tej gramatyki do generowania parser dla Pythona w języku Python. Mam problem z tym, jak wyrazić tokeny jako obiekty pyparsingowe.

Oto jak ja wdrożyły inne terminale:

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 jest funkcją, która zwraca odpowiednią akcję parsowania, w zależności od jej argumentów.

Jestem świadomy funkcji pomocnika pyparsing.indentedBlock, ale nie mogę wymyślić, jak przyjąć to do gramatyki bez tokena PEER.

(Spójrz na pyparsing souce code aby zobaczyć, co mówię)

Można zobaczyć mój kod źródłowy całości: http://pastebin.ca/1609860

Odpowiedz

10

Istnieje kilka przykładów na wiki pyparsing Examples page które mogłyby dać Niektóre spostrzeżenia:

Aby korzystać pyparsing na indentedBlock, myślę, że można zdefiniować suite jak:

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

Zauważ, że indentedGrammarExample.py wstępne terminy włączenie indentedBlock w pyparsing, więc ma swoje własne implementacja wcięcie parsowania.