分析异常中的错误行号

2024-10-06 19:27:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我在pyparsing中定义了一种简单的语言。解析工作正常,但问题在于错误消息。他们显示的行号不对。我在这里展示代码的主要部分

communications = Group( Suppress(CaselessLiteral("communications")) + op + ZeroOrMore(communicationList) + cl + semicolon)

language = Suppress(CaselessLiteral("language")) + (CaselessLiteral("cpp")|CaselessLiteral("python")) + semicolon

componentContents = communications.setResultsName('communications') & language.setResultsName('language') & gui.setResultsName('gui') & options.setResultsName('options')

component = Suppress(CaselessLiteral("component")) + identifier.setResultsName("name") + op + componentContents.setResultsName("properties") + cl + semicolon

CDSL = idslImports.setResultsName("imports") + component.setResultsName("component")

它只在component之前报告正确的行号,但是对于component(即在componentContents中)中的任何错误,它只说组件开始的行号。例如,这是要解析的文本的示例

import "/robocomp/interfaces/IDSLs/Test.idsl";

Component publish
{
    Communications
    {
        requires test;
        implements test;
    };
    language python;
};

如果我错过了python;或test之后的分号。它会说(line:4, col:1)即在{。你知道吗


Tags: testcl错误guilanguagecomponentoptions行号
1条回答
网友
1楼 · 发布于 2024-10-06 19:27:07

这种行为是pyparsing的特征,而不是bug,需要特别小心处理(或解决)。你知道吗

当pyparsing无法匹配复杂表达式中的某个地方时,它会将其解析堆栈放回最后一个完全完整的表达式。您知道在匹配了“component”之后,后面的任何内容都应该是组件定义中的错误,但是pyparsing没有。因此,当在opening关键字之后发生故障时,pyparsing将备份并报告关键字表达式(包括关键字)无法匹配。你知道吗

当您有这样的命令语法时,关键字通常是明确的。例如,在匹配“component”之后,任何不是标识符,后跟括号中的参数列表的内容都将是一个错误。通过将“+”运算符替换为“-”运算符,可以指示pyparsing应该而不是备份过去的“component”。你知道吗

看看你的语法,我会备份并写一个简短的BNF(总是好的做法):

communications ::= 'communications' '(' communicationList* ')' ';'
language       ::= 'language' ('cpp' | 'python') ';'
componentContents ::= communications | language | gui | options
component      ::= 'component' identifier '(' component_contents+ ')' ';'
CDSL           ::= idslImports component

当语法中有关键字时,我总是建议使用KeywordCaselessKeyword,而不是LiteralCaselessLiteralLiteral类不强制单词边界,因此如果我使用Literal("no")作为语法的一部分,它可以匹配“not”或“none”或“nothing”等的前导“no”

下面是我将如何处理这个BNF。(我将使用setResultsName的快捷版本,我发现这样可以使语法本身更清晰):

LBRACE,RBRACE,SEMI = map(Suppress, "{};")
identifier = pyparsing_common.identifier

# keywords - extend as needed
(IMPORT, COMMUNICATIONS, LANGUAGE, COMPONENT, CPP, 
 PYTHON, REQUIRES, IMPLEMENTS) = map(CaselessKeyword, """
    IMPORT COMMUNICATIONS LANGUAGE COMPONENT CPP PYTHON 
    REQUIRES IMPLEMENTS""".split())

# keyword-leading expressions, use '-' operator to prevent backtracking once significant keyword is parsed
communicationItem = Group((REQUIRES | IMPLEMENTS) - identifier + SEMI)
communications = Group( COMMUNICATIONS.suppress() - LBRACE + ZeroOrMore(communicationItem) + RBRACE + SEMI)
language = Group(LANGUAGE.suppress() - (CPP | PYTHON) + SEMI)

componentContents = communications('communications') & language('language') & gui('gui') & options('options')
component = Group(COMPONENT - identifier("name") + Group(LBRACE + componentContents + RBRACE)("properties") + SEMI)

CDSL = idslImports("imports") + component("component")

分析示例组件时使用:

sample = """\
Component publish
{
    Communications
    {
        requires test;
        implements test;
    };
    language python;
};
"""

component.runTests([sample])

提供:

[['COMPONENT', 'publish', [[['REQUIRES', 'test'], ['IMPLEMENTS', 'test']], ['PYTHON']]]]
[0]:
  ['COMPONENT', 'publish', [[['REQUIRES', 'test'], ['IMPLEMENTS', 'test']], ['PYTHON']]]
  - name: 'publish'
  - properties: [[['REQUIRES', 'test'], ['IMPLEMENTS', 'test']], ['PYTHON']]
    - communications: [['REQUIRES', 'test'], ['IMPLEMENTS', 'test']]
      [0]:
        ['REQUIRES', 'test']
      [1]:
        ['IMPLEMENTS', 'test']
    - language: ['PYTHON']

(顺便说一句,我喜欢使用“&;运算符对不同内容与pyparsing的Each类进行无序匹配—我认为这会使解析器更友好、更健壮。结果是Each与“-”运算符有一点冲突,我必须在下一个版本中解决这个问题。)

相关问题 更多 >