java — Как обрабатывать зарезервированные слова для конкретного языка, которые встречаются в выражениях или именах переменных
Задавать вопрос
спросил
Изменено 9 лет, 11 месяцев назад
Просмотрено 1к раз
Я работаю над этой проблемой уже около 4 часов. Вот мой файл грамматики ANTLR V4, который я сократил до простейшего примера.
грамматика Cfscript; компонент : (заявление)* ; заявление : 'возвратное' выражение? ';' | выражениеВыражение ';' ; заявлениеВыражение : выражение ; выражение : начальный | выражение '.' Идентификатор ; начальный : Идентификатор ; Идентификатор : [a-zA-Z0-9_]+ ; WS : [\t\r\n]+ -> пропустить ;
Мой файл содержит
local. return;
Когда я пытаюсь проанализировать этот файл, входящий в
, я получаю следующую ошибку: несоответствующий ввод «возврат», ожидающий идентификатор
. Я не могу понять, почему возникает эта ошибка.
Обновление
Если я правильно понимаю, это потому, что return
является зарезервированным словом в Java, и именно поэтому они структурировали свою грамматику таким образом. На моем языке Coldfusion Cfscript, return
действителен до тех пор, пока он ограничен: local.return
, variable.return
, local["return"]
. Это также верно для if
, else
, savecontent
и многих других слов, все из которых допустимы только внутри областей видимости, но не в качестве первого члена переменной или выражения: if.blah = "something"
неверно, но blah.if = "что-то"
допустимо. Это означает, что я столкнусь с одной и той же проблемой с каждым из этих терминов, поскольку они будут конфликтовать с правилом анализатора, которое их захватывает.
Обобщая то, что сказал Барт, это чистый способ решить эту проблему?
грамматика Cfscript; компонент : (заявление)* ; заявление : K_Return выражение? ';' | выражение ';' ; выражение : начальный | выражение '.' вторичный ; начальный : Идентификатор ; вторичный : К_Возврат | K_Если | K_Еще | Идентификатор ; K_Return: 'возврат'; K_If: 'если'; K_Else : 'еще'; Идентификатор : [a-zA-Z0-9_]+ ; WS : [\t\r\n]+ -> пропустить ;
- Java
- ColdFusion
- ANTLR4
Добавление буквальных токенов внутри парсера, как вы делаете с 'return'
, не означает, что Lexer будет соответствовать строк , как
, так как
.
внутри второй альтернативы в вашем правиле выражения
: выражение
'.' Идентификатор
Если вы хотите сопоставить "return"
как ключевое слово и как идентификатор на вашем языке, вам нужно создать правило парсера, которое соответствует обоим Идентификатор
s и ключевые слова:
выражение : начальный | выражение '. ' идентификатор ; начальный : идентификатор ; идентификатор : Идентификатор | К_Возврат ; // Лучше явно определять их, а не записывать ключевые слова внутри правил парсера К_Возврат : 'возвращаться' ; Идентификатор : [a-zA-Z0-9_]+ ;
4
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью GoogleЗарегистрироваться через Facebook
Зарегистрируйтесь, используя электронную почту и пароль
Опубликовать как гость
Электронная почта
Обязательно, но не отображается
Опубликовать как гость
Электронная почта
Требуется, но не отображается
Джон МакФарлейн - Beyond Markdown
Первоначально это эссе было опубликовано по адресу https://talk.
При разработке Commonmark мы старались, насколько это возможно, оставаться верным оригинальному описанию синтаксиса Markdown Джона Грубера. Мы отклонялись от него лишь изредка, в интересах устранения двусмысленность и увеличивающееся единообразие, а с добавлением нескольких элементы синтаксиса, которые теперь практически вездесущи (например, огороженный код блоки и краткие справочные ссылки).
Есть очень веские причины для такого консерватизма. Но это уважение к прошлому сделало спецификацию CommonMark очень сложный зверь. Есть 17 принципы, управляющие ударением, например, и эти правила по-прежнему оставляют дела нерешенными. Правила для списка элементы и блоки HTML тоже очень сложный. Все эти правила приводят к неожиданным результатам иногда, и они делают написание парсера для CommonMark сложным роман. Временами я отчаиваюсь в том, чтобы добраться до спецификации, которая стоит того, чтобы позвонить 1.0.
Что, если бы мы не были прикованы к прошлому? Что, если мы попытаемся создать легкий синтаксис разметки, который сохраняет все хорошее, что есть в Markdown, в то время как пересмотр некоторых функций, которые привели к раздуванию и сложности в спецификация CommonMark?
Позвольте мне сразу прояснить, что я не предлагаю никаких изменений в цели проекта Commonmark. Если эти размышления к чему-нибудь приведут, вероятно, это должен быть совершенно новый проект под новым названием. И, будучи реалистичным, бремя поддержания обратной совместимости легкий по сравнению с огромными практическими затратами на перемещение существующих системы на новый облегченный язык разметки. Тем не менее... я думаю, что это может быть полезно мечтать.
Далее я рассмотрю шесть функций Markdown, которые я думаю, создали больше всего трудностей, и я предложу, как каждая боль точку можно исправить.
1. Акцент
В Markdown выделение создается за счет окружающего текста *
или _
символа, *вот так*
.
Сильный акцент создается путем их удвоения, **вот так**
. Все это звучит очень просто, и это
визуально ясно, какой из них является сильным акцентом.
К сожалению, этих простых утверждений недостаточно, чтобы точно определить синтаксис. Рассмотрим, например,
**этот* текст**
Наши простые правила согласуются с обоими этими показаниями:
-
это* текст
-
этот текст*
Итак, чтобы полностью указать разбор выделения, нам нужны дополнительные правила. 17 обескураживающе сложных правил в спецификации CommonMark предназначены для форсировать виды чтений, которые люди сочтут наиболее естественными.
Мне кажется, что использование двойных символов для сильного
ударение, и возможность выделения даже части слова, как в fan*tas*tic
, сделали проблему с указанием упора
синтаксический анализ намного хуже, значительно увеличивая неоднозначность, которую должна иметь спецификация.
решать. В зависимости от контекста, строка из трех ***
в
середина слова может быть любой из следующих:
- Символ
*
, за которым следует начало сильного акцент. - Конец сильного ударения, за которым следует
*
характер. - Конец обычного выделения, символ
*
, затем начало нормального ударения. - За окончанием сильного акцента следует начало нормального акцент.
- За концом обычного акцента следует начало сильного акцент.
- Конец обычного ударения, за которым следует буквальный
. - Литерал
**
с последующим началом нормального акцент. - Литерал
***
.
Как закрепить упор
Чтобы значительно уменьшить двусмысленность, мы можем удалить двойное
разделители символов для сильного выделения. Вместо этого используйте один _
для штатного упора, и одинарный *
для
сильный акцент. Акцент теперь будет начинаться с левого фланга, но не
правосторонний разделитель и заканчивается правосторонним, но не
левосторонний разделитель того же вида.
Для выделения внутри слова нам потребуется специальный синтаксис:
вентилятор~_tas_~tic
Акцент внутри слова встречается крайне редко, так что это хороший компромисс.
это немного сложнее, в обмен на упрощение правил (и
концептуальная модель) для акцента в целом. Специальный персонаж ~
здесь действует как пробел для разбора акцента
(позволяя внутрисловному _
начинать и заканчивать ударение), но
не отображается как пробел. (Таким образом, он ведет себя как экранированный пробел
в reStructuredText.)
Добавлено 22.04.2022: Это также дало бы нам способ выразить
что-то, что в настоящее время невыразимо невыразимо в общем знаке: a[b]c
. На данный момент никак
написать это с правилами общего знака, так как в a*[b]*c
первый *
правофланговый и самый
второй *
левофланговый. Но с предложенным синтаксисом это
можно записать как a~_[b]_~c
.
Обычная обработка ссылок делает невозможным классифицировать любой элемент синтаксиса, пока весь документ не будет проанализирован. Например, рассмотрим
[фу] [бар] [баз] [бар]: адрес
Это интерпретируется как
foo[баз]
Но предположим, что мы определяем ссылку для на базе
вместо бар
:
[фу] [бар] [баз] [баз]: адрес
Тогда получаем:
[foo]бар
Таким образом, мы не можем сказать, является ли [foo]
буквально заключенным в квадратные скобки
текст или ссылка с описанием ссылки foo
, пока мы не проанализируем
весь документ.
Это очень затрудняет подсветку синтаксиса, а также усложняет написание парсеров. Например, вы не можете парсить ссылки, то разрешать ссылки в AST после анализа документа.
Как исправить справочные ссылки
Сделать ссылочные ссылки узнаваемыми только по их форме, независимыми какие ссылки определены в документе. Таким образом,
[фу] [бар] [баз]
будет проанализировано как ссылка с текстом ссылки foo
куда угодно
URL определяется для ссылки бар
(или ничего, если нет
определено), за которым следует буквальный текст [баз]
.
Ссылки на ярлыки, такие как
[фу] [foo]: адрес
пришлось бы запретить (если только мы не собирались заставлять писателей экранировать все буквальные скобки). Компактная форма может быть вместо этого используется:
[фу] [] [foo]: адрес
Это немного больше, но ясно и недвусмысленно, что есть ссылка.
3. Кодовые блоки с отступом и списки
Разбор блоков кода с отступом прост, но их присутствие усложняет правила для элементов списка.
При указании синтаксиса для элементов списка нам нужно указать, насколько далеко содержимое должно иметь отступ, чтобы считаться частью списка элемент. Первоначальные документы синтаксиса Markdown намекали на «четыре пробела». правило», требующее отступа в четыре пробела, но реализации редко последовало за этим, и большинство людей находят нелогичным, что 9-- содержимое должно быть с отступом сюда.
Это неплохое правило, но оно добавляет сложности: нужно следить не только позиции маркера списка, но и позиции первое содержимое, не являющееся пробелом, которое следует за ним. И тут нужен спец. правила для таких случаев, как пустые элементы списка и элементы списка, начинающиеся с код с отступом. Наконец, многие до сих пор находят удивительным, что для например, это не вложенный список:
- а - б
Таким образом, можно спросить: почему бы просто не потребовать, чтобы содержимое списка элемент должен иметь отступ хотя бы на один пробел после маркера списка? Это очевидное минимальное правило. Что блокирует это наличие кода с отступом блоки. Если контент блочного уровня под элементом списка начинается с одного пробела отступ после маркера списка, тогда код с отступом должен быть с отступом в пять пробелов после маркера списка. Мало того, что это несовместимо с восемью пробелами, указанными в исходном синтаксисе Markdown описание, это приводит к ужасным результатам с более длинными маркерами списка:
99. Вот мой пункт списка. И это код с отступом! Хотя это совпадает с абзацем выше!
Подводя итог: большая часть сложности правил для элементов списка мотивировано необходимостью иметь дело с блоками кода с отступом.
Как исправить отступ кодовые блоки и списки
Огражденные блоки кода теперь обычно предпочтительнее кодовых блоков с отступом, потому что вы можете указать синтаксис для выделения, и вам не нужно отступ/отступ при копировании и вставке кода. Поскольку у нас есть огороженный код блоки, нам не нужны блоки кода с отступом. Итак, мы можем просто избавиться от их.
Это освобождает отступ для более гибкого использования для обозначения списка вложенности, и мы можем принять простое и очевидное правило, что содержимое элемента списка должен иметь отступ не менее одного пробела относительно списка маркер.
Еще одним преимуществом удаления блоков кода с отступом является то, что начальный отступы теперь можно вообще игнорировать, за исключением тех случаев, когда они влияют на списки.
4. Необработанный HTML
С самого начала вы могли вставлять необработанный HTML в Markdown документы, и он будет передан дословно. Идея в том, что вы может вернуться к необработанному HTML для всего, что не может быть выражено в простой текст.
Звучит проще, чем есть на самом деле. С начала, Markdown.pl
различает встроенный и блочный уровни
HTML. Встроенные теги HTML передавались дословно, но их содержимое
можно интерпретировать как Markdown:
**привет**
даст вам
привет
HTML-контент блочного уровня, как было оговорено, должен быть разделен пустые строки, а начальный и конечный теги не должны иметь отступ. В таком HTML-блоки, все будет передаваться дословно, а не интерпретируется как уценка. Итак,
<дел> *привет* дел>
даст вам
<дел> *привет* дел>
Это вызвало несколько проблем. Во-первых, как мы идентифицируем блочный уровень
содержание? Нужно ли жестко запрограммировать список HTML-элементов, которые могут измениться?
по мере развития HTML? Как насчет таких элементов, как
, которые
может происходить во встроенном или блочном контексте?
Во-вторых, как насчет блочного HTML, который не разделен должным образом и с отступом?
приветпривет
Должны ли синтаксические анализаторы рассматривать его как встроенный HTML и генерировать неверный HTML?
В-третьих, как определить конец блока HTML? Учитывая, что теги
могут быть вложенными, для этого требуется нетривиальный анализ HTML. выпущенный
версия CommonMark для блоков HTML была разработана, чтобы упростить
анализировать необработанные блоки HTML (без неопределенного просмотра вперед или полного
реализация парсинга HTML), а также сделать возможным
авторам включать содержимое CommonMark в HTML-теги блочного уровня, если
они хотели. Но результат довольно сложный: семь различных пар
начальных и конечных условий. Правила для встроенного HTML также сложны,
с большим количеством определений. Кроме того, поскольку Markdown стал полезен не только для создания
HTML, но для создания документов в различных форматах
то, как HTML выделяется для необработанной передачи, стало казаться немного
произвольный. Тем, кто пишет в других форматах, будет полезен способ
пройти через сырой контент, тоже. Вместо того, чтобы проходить через необработанный HTML, мы должны ввести специальный
синтаксис, который позволяет передавать необработанный контент любого формата. Для этого
мы можем перегрузить наши существующие контейнеры для необработанных строк: диапазоны кода и
кодовые блоки: Но мы можем сделать и LaTeX: Мы могли бы даже передать различное необработанное содержимое в разные
форматы, например включая версии HTML и LaTeX сложного
фигура. Может ли список прерывать абзац, как здесь? Оригинальная документация по синтаксису Markdown не решает этого вопроса, но Однако было сделано одно исключение: когда текст абзаца сам по себе часть элемента списка, пустая строка не требуется. Если бы это исключение не было сделано, то мы бы не смогли
распознать вложенный список в этом случае: Размышляя о спецификации CommonMark для элементов списка, мы поняли
что поведение не содержит списка, тогда не содержит подсписка. Мы считаем, что принцип единообразия
это важно. Действительно, то, как мы указываем элементы списка и блочные кавычки
предполагает это. Это означает, что мы оказались перед выбором: либо требовать
пустая строка между текстом абзаца и следующим списком или списки разрешений
прерывать абзацы и рисковать случайным толкованием абзаца
текст в виде списка. Мы выбрали первый вариант, чтобы исключить его из обсуждения, поскольку он
в Markdown очень распространено иметь узкие подсписки без предшествующего
пустая строка. Поэтому мы выбрали второй вариант, смягчив ущерб
с уродливой эвристикой (мы позволяем только упорядоченному списку прерывать
абзац, когда номер списка равен Нам нужна пустая строка между текстом абзаца и списком.
Всегда. То есть даже в подсписках. Таким образом, чтобы составить плотный список с
подсписок, вы должны написать: Мы будем говорить, что список плотный, если он содержит хотя бы одну пару элементов
без пустой строки между ними, поэтому в приведенном выше примере внутренний список
плотный, а внешний список - нет. Чтобы сжать оба списка: Markdown не предлагает общего способа добавления атрибутов (таких как классы или
идентификаторы) к элементам. Это лишает его нативного способа создания
внутренние ссылки на разделы документа. (Многие реализации имеют
представил несколько разных способов автоматической генерации идентификаторов
из заголовков.) Это также лишает его естественного механизма расширения.
В Markdown есть контейнеры для встроенных строк (например, выделения), блоков (например, block
цитата), и необработанный встроенный контент (кодовые области), и необработанный блочный контент (код
блоки). Если бы к ним можно было присоединить произвольные атрибуты, они могли бы
манипулировать фильтрами для получения очень гибкого вывода. Например,
можно рассматривать блочную цитату с классом «предупреждение» как предупреждение
предостережение, или можно рассматривать кодовый блок с классом «точка» как
точечная диаграмма graphviz, которая будет отображаться как изображение. В настоящее время, однако,
единственный способ прикрепить атрибуты к элементу - это выпадающий список
HTML. Введите синтаксис для спецификации атрибута. Вслед за пандоком,
используйте фигурные скобки Разрешить добавление атрибутов в строку до любого блока
элемент и непосредственно после любого встроенного элемента: Здесь в заголовок добавлен идентификатор Спецификаторы атрибутов должны помещаться в одну строку, но можно использовать несколько
(и затем будут объединены): Возможно, было бы полезно добавить синтаксис для неукрашенного встроенного
spans и огороженный универсальный блочный контейнер, как в pandoc. Но мы можем
использовать выделение для встроенного контейнера и кавычки для блока
контейнер, так что это не было бы абсолютно необходимым. Акцент Справочные ссылки Код Списки HTML Атрибуты Markdown.pl
создала недопустимый HTML для
дважды вложенный элемент Как исправить необработанный HTML
Это необработанный HTML: ` jpg">`{=html}.
А вот HTML-блок:
```{=html}
<дел>
<дел>
```
```{=латекс}
\begin{tikzpicture}
\node[inner sep=0pt] (Рассел) в (0,0)
{\includegraphics[width=0,25\textwidth]{bertrand_russell.jpg}};
\node[inner sep=0pt] (белая точка) в (5,-6)
{\includegraphics[width=0,25\textwidth]{alfred_north_whitehead.jpg}};
\draw[<->,толстый] (russell.south east) -- (whitehead.north west)
node[midway,fill=white] {Принципы математики};
\end{tikzpicture}
```
5. Списки и пустые строки
Проверка абзаца.
- Пункт один
- Пункт второй
Markdown.pl
и его набор тестов требуют пустой строки между
текст абзаца и следующий список. Как показывает набор тестов, это
требование было введено во избежание случайного создания
списки по таким вещам, как: Я думаю, что он весил 200 фунтов, может быть, даже
220. Но он был не выше пяти футов ростом.
- Параграф первый
параграф второй
- элемент подсписка один
- элемент второго подсписка
- а
- б
- с
- д
Markdown.pl
нарушает то, что мы назвали принцип единообразия, который гласит, что содержимое списка
элемент должен иметь то же значение, что и за пределами списка
элемент. Этот принцип подразумевает, что если а
- б
- с
- а
- б
- с
- д
1
). Как исправить списки и пробелы
строки
- а
- б
- с
- д
- а
- б
- с
- д
6. Атрибуты
Как исправить атрибуты
{}
для этого. Идентификатор указывается с #
. Простое слово рассматривается как класс (или начальный .
может потребоваться как в pandoc). Используйте =
для
произвольный атрибут ключ/значение. {#мой заголовок}
# *Синий заголовок*{синяя позиция=левая}
myheader
блок, а класс синий
и атрибут ключ/значение position=left
добавляются к выделенному тексту Синий Название
. {#моепредупреждение}
{предупреждение}
> Не пытайтесь повторить это дома!
> Это может быть опасно.
~
ведет себя как пробел в том, что касается разбора акцента, но визуализируется как
ничего.
теперь будет восприниматься как обычный текст и
сбежал.
{=ФОРМАТ}
; в блочном контексте — огороженный блок кода с информацией
строка {=ФОРМАТ}
. {класс #идентификатор ключ=значение}
.