Как использовать SDF {избегать} в негодяях MPL
Я пытаюсь разработать грамматику острова, используя Rascal 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
Например, если я анализирую приведенный выше код, я получаю дерево разбора, которое выглядит следующим образом:
Насколько я могу судить из Документации Rascal, использование "приоритетного" оператора в моём случае может не подходить, но я не вижу других возможностей. Я предполагаю, что есть способ, потому что авторы негодяев ясно заявляют, что каждая грамматика SDF может быть преобразована в негодяйскую грамматику.
Есть ли способ воспроизвести функциональность SDF {избежать} с помощью негодяев MPL? Или можно как-то отфильтровать лес разбора, повторно применяя приоритеты?
1 ответ
Краткий ответ: избегайте в sdf2 фильтр разбора постов. В негодяях вы можете определить их самостоятельно, см. https://github.com/cwi-swat/rascal/blob/master/src/org/rascalmpl/library/lang/sdf2/filters/PreferAvoid.rsc пример, который имитирует sdf2 избегайте поведения, не игнорируя цепи впрыска и не считая. Вы можете импортировать его в свою грамматику и использовать теги @avoid и @prefer, как в sdf2, или написать свои собственные фильтры.
Предостережение: избегать, как правило, было недостаточно для определения поведения воды в sdf2, а также не в негодяях. Причина в том, что вода может стать длиннее, чем ее альтернатива. Предпочитать и избегать можно выбирать только из вариантов одинаковой длины с точки зрения длины субстанции. Один верный, но медленный способ борьбы с водой в негодяях - это считать ее в каждой альтернативе и выбирать производные с меньшим количеством воды.
Еще одна проблема, связанная с "предпочитай и избегай", заключалась в том, что виды использования начнут создавать помехи, особенно когда их подсчитывают. Этого можно избежать в негодяях, специализируя фильтры для определенных нетерминалов или даже альтернативных правил.
Другой вариант - использовать \ и! операторы снятия с охраны. Смотрите руководство. Тем не менее, все и все, что я считаю опцией фильтрации после анализа, в настоящее время является лучшим способом справиться с островными грамматиками, потому что вы контролируете то, что происходит.