Я пытаюсь разработать грамматику острова, используя Мошенник MPL, но я столкнулся с проблемой:
При внедрении островной грамматики в SDF очень распространенным подходом является определение «всеохватывающего» производства воды с использованием атрибута {избежать}. Это препятствует тому, чтобы синтаксический анализатор использовал эту продукцию, если другие применимы. Это позволяет указать поведение по умолчанию это может быть отменено другими производственными процессами, не порождая неясностей. Очень простой пример этого будет:
context free syntax
Chunk* -> Input
Water -> Chunk
lexical syntax
~[\t\n\ ]+ -> Water {avoid} // avoid the Water production
Я попытался воспроизвести это поведение с Rascal MPL. Моя цель — создать островную грамматику, которая собирает все условные директивы препроцессора внутри фрагмента кода C / C ++ и пропускает остальную часть ввода с использованием Water productions.
layout LAYOUT = [\t\n\ ];
lexical WATER = ![\t\n\ ]+;
start syntax Program = Line*; // program consists of lines
syntax Line = ConditionalDirective // preprocessor directives
> WATER; // catch-all option
syntax ConditionalDirective = "#ifdef"| "#ifndef"| "#if"| "#elif";
Я попытался создать эффект {избежать}, дав ConditionalDirective производство с более высоким приоритетом, используя оператор «>», но это, очевидно, не работает. Дерево разбора все еще содержит неясности.
#ifdef asd
Например, если я анализирую приведенный выше код, я получаю дерево разбора, которое выглядит следующим образом:
Насколько я могу судить по Мошенническая документация, использование «приоритетного» оператора в моём случае может не подходить, но я не вижу других возможностей. Я предполагаю, что есть способ, потому что авторы негодяев ясно заявляют, что каждая грамматика SDF может быть преобразована в негодяйскую грамматику.
Есть ли способ воспроизвести функциональность SDF {избежать} с помощью негодяйского MPL? Или можно как-то отфильтровать лес разбора, повторно применяя приоритеты?
Краткий ответ: избегайте в sdf2 фильтр разбора постов. В негодяй вы можете определить это сами, смотрите https://github.com/cwi-swat/rascal/blob/master/src/org/rascalmpl/library/lang/sdf2/filters/PreferAvoid.rsc для примера, который имитирует sdf2, избегает поведения, не игнорируя цепочки впрыска и не считая. Вы можете импортировать его в свою грамматику и использовать теги @avoid и @prefer, как в sdf2, или написать свои собственные фильтры.
Предостережение: избегать, как правило, было недостаточно для определения поведения воды в sdf2, а также не в негодяях. Причина в том, что вода может стать длиннее, чем ее альтернатива. Предпочитать и избегать можно выбирать только между вариантами одинаковой длины с точки зрения длины субстанции.
Один верный, но медленный способ борьбы с водой в негодяях — это считать ее в каждой альтернативе и выбирать производные с меньшим количеством воды.
Еще одна проблема, связанная с «предпочитай и избегай», заключалась в том, что виды использования начнут создавать помехи, особенно когда их подсчитывают. Этого можно избежать в негодяях, специализируя фильтры для определенных нетерминалов или даже альтернативных правил.
Другой вариант — использовать \ и! операторы снятия с охраны. Смотрите руководство. Тем не менее, все и все
Я считаю, что опция фильтрации после разбора в настоящее время является лучшим способом борьбы с островными грамматиками, потому что вы контролируете происходящее.
Других решений пока нет …