Как работать с пробелами в грамматике?

Я хочу создать парсер / лексер для упрощенной версии LISP. Вот спецификации бизонов / лексеров:

/* Lexer file */
"(" {return OP;}
")" {return CP;}
[0-9]+ {return NUM;}
["][a-zA-Z]*["] { return STR; }
[ 

f]     { /*do nothing*/}
. {return INVALID_TOKEN;}

/* Bison file */
start_expr: components_list

components_list : /*nothing*/
     | components_list component

 component : OP STR NUM CP

Такая строка соответствует грамматике ("f" 1) ("f"1)( "f" 1)( "f" 1 ) . Но выражение ("f"1) выглядит довольно ужасно для меня, я решил добавить явно грамматические разделители в грамматику (использование токена WHITESPACE вида [ f]+ ). Что-то вроде того:

opt_wspace : /*nothing*/
   | WHITESPACE

start_expr: components_list

components_list : /*nothing*/
     | components_list component

 component : OP opt_wspace STR WHITESPACE NUM opt_wspace CP

Но сейчас (как по мне) грамматика выглядит ужасно, но выражения вида ("f"1) запрещены. Еще один момент: теперь я могу легко ошибиться в грамматике. Например, такие выражения не будут анализироваться ("f" 1) ("f" 1) (я забыл добавить использование opt_wspace в components_list ).

Итак, мой основной вопрос - как работать с разделителями / пробелами в грамматике? Я посмотрел грамматику python ( https://github.com/python/cpython/blob/master/Grammar/Grammar ), но, похоже, в нем нет упоминаний о пробельных выражениях / токенах. Вот небольшая цитата:

stmt: simple_stmt | compound_stmt

simple_stmt: small_stmt (';' small_stmt) * [';'] NEWLINE

small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | нелокальный_stmt | assert_stmt)

expr_stmt: testlist_star_expr (annassign | augassign (yield_expr | testlist) | [('=' (yield_expr | testlist_star_expr)) + [TYPE_COMMENT]])

Всего 1 ответ

Автоматический диспенсер мыльной пены от xiaomi.


Ни один из известных мне багов (или вообще языков программирования в целом) не заставляет вас ставить пробелы между токенами подобным образом. Например, такие вещи, как (display"hello") или (format t"~d"42) работают нормально в Scheme и Common Lisp соответственно. Так что то, что вы пытаетесь сделать, обычно не делается, и я бы порекомендовал просто не делать этого.

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

[0-9]+ {return NUM;}
["][^"]*["] { return STR; }
(["][^"]*["]|[0-9]+){2,} { return INVALID_TOKEN; }

Таким образом, INVALID_TOKEN будет генерироваться всякий раз, когда несколько строк или чисел появляются рядом друг с другом, и между ними ничего нет. Шаблон для этого будет становиться все более и более сложным, поскольку вы добавляете больше типов токенов, которые вы не хотите использовать рядом друг с другом (например, идентификаторы).

PS: очень необычно разрешать только буквы в строках, поэтому я изменил регулярное выражение для строковых литералов в приведенном выше. Вы, вероятно, захотите настроить его дальше, чтобы включить двойные кавычки в строке.


Есть идеи?

10000