Написать парсер, который анализирует грамматику, затем трансформируют из синтаксического анализа дерева до требуемой записи.
Само преобразование достаточно прост:
- заменить '#' комментарий поручителей по '//'
- заменить ':' лексемы ':: ='
- заменить '[' токенов by '('
- заменить ']' токены на ')?'
Подходящая мета-грамматика, в W3C notation, является
Grammar ::= Rule+ EOF
Rule ::= Nonterminal ':' Alternatives
Alternatives
::= Alternative ('|' Alternative)*
Alternative
::= (Symbol ('*' | '+')?)*
Symbol ::= Nonterminal
| Terminal
| '(' Alternatives ')'
| '[' Alternatives ']'
<?TOKENS?>
Nonterminal
::= [a-z] [a-z_]*
Terminal ::= [A-Z] [A-Z_]*
| "'" [^']+ "'"
EOF ::= $
IgnorableWhitespace
::= [ #x9#xA#xD]+
| '#' [^#xA]* [#xA]
/* ws: definition */
Поместите его в grammar.ebnf
, а затем использовать REx создать анализатор для него, например, кодированного в XQuery, используя эту команду:
-xquery -tree
Это дает вам модуль XQuery grammar.xquery
. Далее, поставить грамматику питона в python.grammar
, и эта программа XQuery в transform.xquery
:
import module namespace p="grammar" at "grammar.xquery";
declare option saxon:output "method=text";
declare variable $input as xs:string external;
for $token in p:parse-Grammar(unparsed-text($input))//text()
return
if (starts-with(normalize-space($token), "#")) then
replace($token, "((^|
)[\s])*#", "$1//")
else
switch ($token)
case ":" return "::="
case "[" return "("
case "]" return ")?"
default return $token
Затем используйте Saxon запустить его:
java net.sf.saxon.Query transform.xquery input=python.grammar > python.ebnf
В результате то, что вы искали.
Конечно, вы также можете использовать свой любимый текстовый редактор, чтобы сделать глобальное замещение тем же. Это просто гораздо интереснее, чтобы сделать это правильно.