كيف يمكنني تحليل المسافات البادئة و decdents مع دخول؟
-
20-09-2019 - |
سؤال
فيما يلي مجموعة فرعية من قواعد النحوية:
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
(يمكنك قراءة القواعد الكاملة في مستودع Python SVN: http://svn.python.org/.../grammar)
أحاول استخدام هذه القواعد النحوية لتوليد محلل للبيثون ، في بيثون. ما أواجه مشكلة في كيفية التعبير عن INDENT
و DEDENT
الرموز ككائنات مثيرة.
إليكم كيف قمت بتنفيذ المحطات الأخرى:
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
هي وظيفة تُرجع إجراء التحليل المقابل ، اعتمادًا على حججها.
أنا على علم pyparsing.indentedBlock
وظيفة المساعد ، لكنني لا أستطيع معرفة كيفية تبني ذلك إلى قواعد اللغة بدون PEER
رمز.
(انظر الى رمز سويس لمعرفة ما أتحدث عنه)
يمكنك رؤية رمز المصدر الكامل هنا: http://pastebin.ca/1609860
المحلول
هناك بعض الأمثلة على الويكي الغامق صفحة أمثلة يمكن أن يعطيك بعض الأفكار:
لاستخدام Pyparsing's indentedBlock
, ، أعتقد أنك ستحدد suite
مثل:
indentstack = [1]
suite = indentedBlock(stmt, indentstack, True)
لاحظ أن indentedGrammarExample.py
قبل تواريخ إدراج indentedBlock
في غصين ، وكذلك تنفيذها الخاص من التحليل المسافة البادئة.