Python 解析a";简单的;语法

Python 解析a";简单的;语法,python,parsing,grammar,Python,Parsing,Grammar,提前道歉;我确信这个问题对于那些习惯于使用解析器和语法的人来说几乎是白痴,但这些对我来说都是陌生的话题,而这正是我试图温和地进入一个需要它们的实际案例的尝试 我想为以下“语言”编写一个解析器,其中包含一个“特殊结构”,如下所示: \command[ options ]{ contents } program := element+ element := command | literal literal := (not '\')+ command := '\'identifier optio

提前道歉;我确信这个问题对于那些习惯于使用解析器和语法的人来说几乎是白痴,但这些对我来说都是陌生的话题,而这正是我试图温和地进入一个需要它们的实际案例的尝试

我想为以下“语言”编写一个解析器,其中包含一个“特殊结构”,如下所示:

\command[ options ]{ contents }
program := element+
element := command | literal
literal := (not '\')+

command := '\'identifier options? '{' program '}'
options := option | options ',' option
option  := identifier '=' value
value   := number | string

string  := '"' (escape | not '\' or '"')* '"'
escape  : = '\' char
内容可以是任何内容,包括嵌套命令,并且可能包含转义括号或反斜杠
\{\\\\\\\\
。我意识到“任何东西”都不是特定的,但理想情况下,它们应该通过匹配括号(不包括转义括号)来确定,如果可能的话

选项应该是以逗号分隔的赋值表达式列表,例如
name=value
,但该值可以是包含
=
字符的带引号的字符串。最后,前面的
名称
命令
应该验证正则表达式
\w[\w\d\.+*]*
——也就是说,第一个字符应该是字母,其余字符应该是字母、数字或
中的一个*

用正则表达式编写这段代码似乎过于复杂(例如,因为值可能包含带引号的字符
,=
,否则将分隔赋值或名称/值对)。因此,我认为这里最合适的工具是语法,但尽管阅读了肤浅的内容,但我不确定如何编写它(BNF、PEG等),使用哪种类型的解析器(LR、recursive Delege等),以及如何在实际程序中使用解析输出

我更喜欢Python的答案,这解释了标记,但是如果必要/更合适的话,我当然会非常乐意使用这些工具的组合



注意:这与乳胶无关。我当然意识到了这种相似性,但LaTeX比以前的语言要复杂得多,例如,字符代码根据上下文的不同而变化。我只是想问一个(我认为)足够简单的实际例子,但对我的日常工作已经很有用。

首先,用你喜欢的任何符号更正式地表达你的语法。e、 例如,根据您的描述,EBNF如下所示:

\command[ options ]{ contents }
program := element+
element := command | literal
literal := (not '\')+

command := '\'identifier options? '{' program '}'
options := option | options ',' option
option  := identifier '=' value
value   := number | string

string  := '"' (escape | not '\' or '"')* '"'
escape  : = '\' char
然后将其提供给解析器生成器(pyParsing、pyYACC、ANTLR),或者手工编写解析器。在后一种情况下,自顶向下是最简单的选择:从语法的顶部开始,将每个规则转换为一个函数,该函数将返回一个已解析的AST节点并使用输入,或者不返回任何内容或抛出。例如:

 def program():
    elements = []
    while next_sym():
        elements.append(element())
    return {'type': 'program', 'children': elements}

 def element():
     return command() or literal()

 def command():
     if next_sym() == '\\':
         get_sym()
         ...parse command here
         return {'type': 'command', 'children': ...}
     return None 

其中
next_sym
从输入返回下一个符号(或在EOF上返回
None
),而
get_sym
消耗符号并推进输入缓冲区。

这是(La)TeX吗?否:)LaTeX要复杂得多,包含字符代码、
@
-语句等。从某种程度上来说,这是LaTeX非常强大的限制。我问这个问题主要是因为我想了解一个案例,这个案例在工作中已经很有用,而且(我认为)很简单,可以给出答案。读一个标题中有解析的问题,让人耳目一新,实际上是关于解析的。“内容可以是任何东西”从编写语法分析器的角度来看,没有太多东西可以做。@JohnColeman我的意思是,应该通过匹配括号对来确定内容,但忽略转义括号。语法需要更具体吗?非常感谢;在本例中,是
identifier、number和char
原语,还是应该像您定义其余的那样定义它们?关于
string
定义,部分
not'\'或''
强制对黑色斜杠和双引号进行转义,对吗?取决于您使用的方法,一些生成器提供原语,其他生成器不提供原语,因此您必须使用正则表达式定义它们。