我想为以下“语言”编写一个解析器,其中包含一个“特殊结构”,如下所示:
\command[ options ]{ contents }
内容可以是任何内容,包括嵌套命令,并且可以包含转义括号或反斜杠\{ \} \\
。我意识到“任何事情”并不具体,但理想情况下,如果可能的话,应该通过匹配括号(不包括转义的括号)来确定它们。
选项应该是以逗号分隔的分配表达式列表,例如name = value
,但值可以是包含=
或,
个字符的带引号的字符串。最后,前一个name
和command
应该验证正则表达式\w[\w\d\._-+*]*
- 也就是说,第一个字符应该是一个字母,剩下的字符应该是字母,数字或其中一个. _ - + *
。
使用正则表达式编写它似乎过于复杂(例如,因为值可能包含带引号的字符, =
,否则会分配赋值或名称/值对)。所以我认为这里最合适的工具是语法,但是尽管有表面的读数,我只是不确定如何编写它(BNF,PEG等?),使用哪种类型的解析器(LR,递归正确等等?) ,以及如何在实际程序中使用解析输出。
我更喜欢Python的答案,它解释了标签,但当然,如果必要/更适合,我会非常满意这些工具的组合。
注意:这不是关于LaTeX。我认识到当然是相似的,但是LaTeX比以前的语言复杂得多,例如字符代码根据上下文而变化。我只是要求一个实际的例子(我认为)对于SO来说很简单,但在我的日常工作中对我来说已经很有用了。
答案 0 :(得分:7)
首先以更正式的方式表达您的语法,无论您喜欢什么样的符号。例如,根据您的描述,EBNF将是这样的:
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
使用该符号并前进输入缓冲区。