Неопределенная двусмысленность в Clojure

У меня проблема с неоднозначным разбором в инсте. Вот грамматика:

(def yip-shape
  (insta/parser
   (str/join "\n"
             ["S = ( list-item | heading | text-block )*"

              ;; lists and that
              "list-item = list-level <ws> anything"
              "list-level = #' {0,3}\\*'"

              ;; headings
              "heading = heading-level <ws> ( heading-keyword <ws> )? ( heading-date <ws> )? anything <eol?>"
              "heading-level = #'#{1,6}'"
              "heading-date = <'<'> #'[\\d-:]+' <'>'>"
              "heading-keyword = 'TODO' | 'DONE'"

              "text-block = anything*"

              "anything = #'.+'"
              "<eol> = '\\r'? '\\n'"
              "<ws> = #'\\s+'"])))

Проблема с заголовком, как ## TODO Done - Я могу понять, почему существует двусмысленность, я просто не уверен в том, как лучше ее решить. НАПРИМЕР

(insta/parses yip-shape "## TODO Done.")

Производит:

([:S [:text-block [:anything "## TODO Done."]]] 
 [:S [:heading [:heading-level "##"] [:anything "TODO Done."]]] 
 [:S [:heading [:heading-level "##"] [:heading-keyword "TODO"] [:anything "Done."]]])

Последний из которых - результат, который я ищу. Как лучше всего устранить двусмысленность и сузить результат до последнего в этом списке?

2 ответа

Грамматики предназначены для анализа структурированных данных. Если вы возьмете в противном случае разумную грамматику и добавите в нее правило "любой старый мусор", вы получите много разборов, которые включают любой старый мусор. Способ устранения неоднозначности состоит в том, чтобы быть более строгим в отношении того, что квалифицируется в вашем правиле "что угодно", или, еще лучше, полностью удалить его и вместо этого фактически проанализировать то, что там происходит.

Один из вариантов - настроить регулярное выражение на "что угодно", чтобы разрешить любой символ, кроме #. Таким образом, он только ест текст до следующего # символа.

Другой вариант - настроить регулярное выражение для "всего", чтобы не допустить использование символа # в качестве первого символа, и запретить символ новой строки в качестве любого символа. Также вероятно хотел бы изменить текстовый блок, чтобы быть (что угодно | eol)*. Таким образом, в этом случае "что-нибудь" будет полностью заполнено символом новой строки, что позволит текстовому блоку обрабатывать текст по одной строке за раз. Когда вы попадете в строку, начинающуюся с #, она не будет воспринята "чем-нибудь", но вместо этого будет выбрана другими правилами.

Это действительно зависит от поведения, которое вы хотите, но вот некоторые стратегии для того, чтобы сделать ваше описание "чего-либо" более точным.

Другие вопросы по тегам