2014-01-30 1 views
1

У меня есть 2 выражение:Как назначить приоритет двум перекрывающимся выражениям? (Ragel)

ident = alpha . (alnum|[._\-])*; 
string = (printable1)+; 
    # Printable includes almost all Windows-1252 characters with glyphs. 
main := (ident % do_ident | string % do_string) 
    # The do_* actions have been defined, and generate tokens. 

Очевидно, что любая идент является строкой. У Ragel есть приоритетные операторы, чтобы преодолеть это. Но независимо от того, как я пытался установить приоритеты, либо некоторые idents выполняют оба действия, либо игнорируются некоторые допустимые строки (допустимые строки с допустимым идентификатором в качестве префикса, например: ab $).

Я нашел один способ обойти это, без использования приоритетов:

main := (ident % do_ident | (string - ident) % do_string) 

Но если у меня есть больше, чем несколько перекрывающего выражения, это будет получить громоздкое. Это единственный практический путь?

Любая помощь с правильным способом для этого будет оценена по достоинству.

+0

У меня такой же вопрос, как и вы. Вы находите хороший ответ? Или просто держите его, как вы предложили? – sim

+0

В итоге я перешел с моим методом выше, вычитая различные определения с более высоким приоритетом из более низких приоритетов. Оказалось, что мне нужно было сделать это только для 4 из 14 образцов. Полученный код не очень хорош, но он работает. –

ответ

1

Взгляните на раздел '6.3 Сканеры' в Ragel Guide.

main := |* 
    ident => do_ident; 
    string => do_string; 
*|; 

Примечание: При использовании сканеров, которые ts, te и act определены на языке хоста.

+0

Проблема с сканерами Ragel заключается в том, что они тестируют входные данные против шаблона _every_, чтобы найти самое длинное совпадение. Но для цитируемых строк у меня есть 4 шаблона, 3 из которых являются правильными подмножествами по умолчанию. Каждая строка будет проверена на 4 шаблона, а для 3 специальных случаев - 2 полных сканирования этой строки. Для неучтенных строк существуют подструктуры _6_ с той же проблемой. Я могу устранить некоторые из них, но совпадение останется. I _can_ сделать это без сканеров, просто немного больше проблем с записью. Против удвоения времени лексинга, мне просто нужно потратить больше времени на кодирование. :( –

+0

Ничего себе, сканер не сработает для вас. У меня нет видимости для вашего большего проекта, но я бы рекомендовал изолировать проблему перекрытия в одном экземпляре машины. Затем просто используйте 'fhold', когда вы можете определить проблема может существовать, 'fgoto' для решения проблемы перекрытия и' fret', чтобы вернуться в основную машину [как в этом примере] (http://www.complang.org/ragel/examples/gotocallret.rl). – emcconville

+0

Глядя на этот пример кода, это намного больше программирования, чем мой метод выше вычитания шаблонов. Пока что мой график имеет 54 состояния и 152 перехода. Ragel генерирует его довольно хорошо, но я обнаружил, что Graphviz ** ужасен ** для просмотра. : P –

1

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

main := (ident %(ident_vs_string, 1) % do_ident | string $(ident_vs_string, 0) % do_string)

Это гарантирует, что уходящая переход после допустимого выражения останавливает машина изучает либо продолжение, либо выход из строки.

Будьте осторожны с тем, как это комбинированное выражение прекращается. Любое выражение следует за идентификатором/строкой, которое должно начинаться с символа, который недопустим ни в одном, так и в том, что выходные переходы хорошо определены.