лексический разбор, вопрос.

bleyman

Как считаете, строчка "10abc" должна разбиваться на интовый литерал и идентифаер или считаться ошибкой?
То есть, когда я пишу регекс для разбора, он должен выглядеть просто как
type1) | (type2) | ... | (typeN \s* )*
или правильней ввести разделение на делиметеры и обычные токены и потребовать, чтобы обычные токены не могли идти подряд?
Первый вариант проще, но может приводить к забавным эффектам.
В питоне реализован первый, строчка "[i + 10for i in range(10)]" парсится корректно.
Для сиподобных синтаксисов мне что-то даже не удаётся придумать синтаксически корректный пример, в котором два обычных токена идут подряд, но так вообще по ходу тоже так же сделано.

bleyman

А, там же ещё строчка не одним регексом парсится вся целиком, а по-кусочкам. То есть жадный-то он жадный, но printu"1" парсить отказывается, потому что он жадно захавывает только первый идентифаер. Что в общем-то правильно.
Так что сделать корректное разделение на обычные токены и делиметеры на уровне лексера вообще как-то очень тяжело. Максимум — эмитить whitespace в качестве токена и уже потом проверять, что два обычных токена разделены вайтспейсом, ну, чисто опечатки отлавливать.
Забавно.

Dasar

в mainstream языках считается, что два "слова" не могут идти подряд.
слово - это число, идентификатор, ключевое слово.
в других случаях, начинаются всякие сложности при разборе выражений.
например, 1e5 - это число; или число, переменная, число?
0x05 - это число или нет?
134ul?

Dasar

кстати не совсем понятно, что такое делимитер?
т.к. слова, например, в сишном синтаксисе могут разделяться пробелом, запятой, скобкой (круглой, фигурной, угловой, квадратной точкой с запятой, знаком операции.
это все определять именно как разделитель?

vall

В питоне реализован первый, строчка "[i + 10for i in range(10)]" парсится корректно.
это скорее всего баг.
АФАИК в оригинальном фортране какой-то капец с пробелами и границами операторов/идентификаторов.

artimon

В Metapost'е 10abc считается как число 10 умножить на переменную abc =)

artimon

Вообще, мне кажется, что регулярными выражениями эту задачу решать не надо. Для этого есть lex/yacc/bison…

hwh2010

выдавай лучше ошибку
если человек пишет 10abc, с большой вероятностью он опечатался либо имеет ввиду 16-ричное число.
Для недесятичных чисел есть у тебя возможность записи?
Лучше был бы, чем разрешать такой изврат.
А и то и другое не получится, потому что буквы используются в 16-ричной записи.

bleyman

> это скорее всего баг.
Что значит баг? Там грамматика такая.
Ещё раз объясняю: есть стандартный способ лексического разбора, который в общем-то описывается немудрящим регесом типа "^ \s* (integer | float | string | identifier | ...)", где на месте integer, float и всего остального стоят конкретные регексы для распознавания соответствующих лексем. Эта штука последовательно применяется к тексту, каждый раз выдёргивая самый длинный кусок, после чего выясняется, какая именно внутренняя скобка заматчила нужное и результат выдаётся дальше, синтаксическому анализатору.
Это тупо самый простой вариант.
Но у него есть непредусмотренные особенности, например та, которую я показал: вначале матчится 10 как интовый литерал, потом for как зарезервированное слово. Это не баг, это фича, то есть регекс написан и интерпретируется правильно, просто такая вот херня выходит.
Мне такая фича что-то не нравится, я размышляю о том, как бы её можно было убить.
Это не очень легко, на самом деле. Я сейчас вижу два варианта, оба используют понятие "обычного токена" и "делимитера". Обычные токены — это все литералы и идентифаеры, делимитеры — это скобки, операторы етс. Так вот:
1) Построить регекс, который захавывает сразу весь текст. Но построить его не тупо приписав к оригинальному звёздочку, а записав на верхнем уровне что-то вроде "delimeter? (token delimeter+)*", где token будет дизъюнкцией всех определений токенов, а delimiter, соответственно, делимитеров И whitespace. Ну или как-то так, не хочется вдаваться, потому что это говно.
Мало того, что регекс получится большой и тормозной, так ещё и начнутся другие загадочные явления. Например, если в оригинале строчка printu"abc" разбивалась на printu и "abc", потому что типа каждый отдельный раз регекс работает жадно, а на верхнем уровне — нормально, то если попробовать сделать так, то эта поебень вполне может разбиться на print и u"abc" (уникодная строчка).
То есть данный конкретный пример наверняка не сработает, но какой-нибудь другой ещё может оказаться. Плохое решение, короче!
2) В явном виде добавить токен whitespace (как разделитель) и фильтр между лексическим и синтаксическим анализом, который будет страшно ругаться, если два токена, непомеченные как разделители, идут подряд.
Вот это правильное решение, ящитаю.

vall

Что значит баг? Там грамматика такая.
вот в ней и баг, нефиг такое разрешать.
парсить можно не только регулярками. разделители позволяют быстро порезать текст на операторы и что-то между ними в несколько строк кода и без использования сложных автоматов.
Оставить комментарий
Имя или ник:
Комментарий: