Новая строка, убегающая от слоя, в комментариях в стиле Си

#ply

Вопрос:

Я пишу простой синтаксический анализатор, используя PLY. Мои комментарии могут выглядеть так

 # this is a single line comment  with an escaped new line   

Моя попытка состоит в том, чтобы использовать здесь состояния. У меня есть

 states = (  ('COMMENT', 'exclusive'), ) tokens = ('COMMENT')  def t_begin_COMMENT(t):  r'#'  t.lexer.begin('COMMENT')   def t_COMMENT_contents(t):  r'.|\n'   t_COMMENT_ignore = r' '  def t_COMMENT_error(t):  pass   def t_COMMENT_end(t):  r'n'  t.lexer.begin('INITIAL')   

Когда я это сделаю

 lexer = lex.lex() string = "# test \ns n4" lexer.input(string) for tok in lexer:  print(tok)  

он должен напечатать 4 (у меня есть для этого другой токен, но сейчас это не имеет значения), но я получаю s и 4 где s все еще комментарий. Как мне написать регулярное выражение для содержимого? Это потому COMMENT , что заканчивается n ?

Ответ №1:

Регулярные выражения Python не дают самого длинного совпадения. Чередование ( | ) в регулярном выражении Python упорядочено; если вы используете шаблон .|\n , то . он всегда будет совпадать (если только строка не пуста), и поэтому \n никогда не будет опробован. Это легче увидеть без символов escape:

 gt;gt;gt; import re gt;gt;gt; re.match(r'.|ab', 'ab') lt;_sre.SRE_Match object; span=(0, 1), match='a'gt; gt;gt;gt; re.match(r'ab|.', 'ab') lt;_sre.SRE_Match object; span=(0, 2), match='ab'gt;  

Мне совсем не понятно, почему вы хотите проделать всю эту работу, а не использовать одно регулярное выражение без необходимости прибегать к состояниям лексера.

 def t_comment(t):  r'#(\n|.)*n'  pass  

(Примечание: я бы предпочел регулярное выражение r'#(\[sS]|.)*' , которое позволяет a избежать чего угодно, в том числе самого себя. Регулярное выражение, которое вы используете, не позволяет вам когда-либо ставить обратную косую черту в конце строки комментария:

 # This will continue, perhaps unexpectedly: \ still a comment  

Кроме того, трейлинг n в любом случае будет проигнорирован, поэтому нет очевидной причины включать его в шаблон, где он может не совпадать, если комментарий находится в самом конце ввода и ввод не заканчивается новой строкой.

Комментарии:

1. Я привык к состояниям, потому что в основном я использую Flex. Спасибо за разъяснение, я не знал, что это изменение было заказано.

2. @Awerde: Я бы использовал точно такое же регулярное выражение в flex. Нет смысла использовать состояния только для того, чтобы избежать операторов повторения.

3. Конечно, в Flex вам не нужно беспокоиться о упорядоченном чередовании. Это «попалось» с Python и другими движками регулярных выражений, совместимыми с Perl. Я считаю, что Javascript-это то же самое. Регулярные выражения Flex используют правила Posix (такие же, как grep), где чередование не упорядочено.