Неожиданное совпадение с регулярным выражением - PullRequest
0 голосов
/ 02 июня 2019

Я пытаюсь создать синтаксический анализатор с использованием C-Bison и Flex.Во Flex у меня есть регулярное выражение, которое совпадает с целыми числами на основе следующего:

  1. Должен начинаться с любой цифры в диапазоне 1-9, за которым следует любое количество цифр в диапазоне 0-9.(напр. Правильно: 1,12,11024 | Неверно: 012)

  2. Может быть подписано (напр. + 2, -5)

  3. Цифра 0 не должна сопровождаться цифрой (0-9) и не должна быть подписана.(напр. Правильно: 0 | Неверно: 012, + 0, -0)

Вот регулярное выражение, которое я создал для выполнения сопоставления: [^ +-] 0 [^ 0-9] | [+ -]? [1-9] [0-9] *

Вот выражение, которое я проверяю: (1 + 1 + 10)

Совпадения:

1
1
10)

И вот мой вопрос, почему он совпадает'10) '?

Причина, по которой я использовал вышеприведенное выражение вместо гораздо более простого, (0 | [+ -]? [1-9] [0-9] *):из-за неспособности синтаксического анализатора распознать неправильные выражения, такие как 012.

Проблема возникает только тогда, когда перед ')' предшествует цифра "0".Однако если «0» предшествуют две или более цифры (например, 100), то «)» не совпадает.

Я точно знаю, удаляю ли я [^ 0-9] изрегулярное выражение не соответствует ')'.

1 Ответ

3 голосов
/ 02 июня 2019

Это соответствует 10(, потому что 1 соответствует [^+-], 0 соответствует 0 и ( соответствует [^0-9].

Причина, по которой я использовал приведенное выше выражение:вместо гораздо более простого (0 | [+ -]? [1-9] [0-9] *) происходит из-за неспособности синтаксического анализатора распознавать неправильные выражения, такие как 012.

Как так?Используя приведенное выше регулярное выражение, 012 будет распознаваться как два токена: 0 и 12.Не приведет ли это к ошибке в вашем парсере?

По общему признанию, это не приведет к очень хорошему сообщению об ошибке, поэтому лучшим подходом было бы просто использовать [0-9]+ в качестве регулярного выражения, а затем использовать действие для проверкиза ведущий ноль.Таким образом, 012 будет единственным токеном, и лексер может выдать ошибку или предупреждение о начальном нуле (я предполагаю, что вы действительно хотите запретить начальные нули - не используйте их для восьмеричных литералов).

Вместо проверки в действии вы также можете оставить свое регулярное выражение, а затем добавить еще одно для целых чисел с начальным нулем (например, 0[0-9]+ { warn("Leading zero"); return INT; }), но я бы пошел с проверкой в ​​действии, поскольку это простая проверкаи это делает регулярное выражение коротким и простым.

PS: Если вы сделаете - и + частью целочисленного токена, что-то вроде 2+3 будет выглядеть как целое число 2, за которым следуетцелое число +3, а не целые числа 2 и 3 с токеном + между ними.Поэтому, как правило, лучше не делать знак частью целочисленного токена и вместо этого разрешать префиксные операторы + и - в анализаторе.

...