2010-12-10 7 views
8

Я переношу компилятор языка программирования на C# из ручного лексера/парсера в Antlr.ANTLR Parser с ручным лексером

Antlr оказывает сильную головную боль, потому что обычно работает в основном, но есть небольшие части, которые не имеют и невероятно болезненны для решения.

Я обнаружил, что большинство моих головных болей вызвано лексерными частями Antlr, а не парсером. Затем я заметил parser grammar X; и понял, что, возможно, у меня мог бы быть написанный вручную лексер, а затем созданный парсером Antlr.

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

+0

Моя рекомендация заключается в том, что вы можете учиться на существующих. Тем не менее, я могу найти только NHibernate, который использует Antlr, и использование довольно ограничено. :( –

+0

* «но тогда есть небольшие части, которые не имеют и невероятно болезненны для решения» * - Нечетная. Лексическая часть языка обычно проще реализовать. Возможно, вы могли бы объяснить, что «мелкие детали» дают вам Проблемы? –

+0

@Bart Kiers У меня возникли проблемы с внедрением диапазонов и несколькими другими функциями (такими как 3.toString() и 3.0.toString()) по-другому, чем в списке, указанном в их FAQ. невероятно просто решить в создаваемом вручную лексере. – luiscubal

ответ

7

Я узнал, как. Возможно, это не лучший подход, но, похоже, он работает.

  1. Antlr парсеров получить параметр ITokenStream
  2. Antlr лексеры сами ITokenSource s
  3. ITokenSource является значительно более простым интерфейсом, чем ITokenStream
  4. Самым простым способом преобразовать ITokenSource к ITokenStream является использование CommonSourceStream , который принимает параметр ITokenSource

Так что теперь нам нужно только сделать 2 вещи:

  1. Отрегулировать грамматику быть парсер только
  2. Реализовать ITokenSource

Регулировка грамматики очень просто. Просто удалите все объявления lexer и убедитесь, что вы объявляете грамматику как parser grammar. Простой пример размещен здесь удобства:

parser grammar mygrammar; 

options 
{ 
    language=CSharp2; 
} 

@parser::namespace { MyNamespace } 

document: (WORD {Console.WriteLine($WORD.text);} | 
     NUMBER {Console.WriteLine($NUMBER.text);})*; 

Обратите внимание, что следующий файл будет выводить class mygrammar вместо class mygrammarParser.

Итак, теперь мы хотим реализовать «поддельный» лексер. я лично использовал следующий псевдокод:

TokenQueue q = new TokenQueue(); 
//Do normal lexer stuff and output to q 
CommonTokenStream cts = new CommonTokenStream(q); 
mygrammar g = new mygrammar(cts); 
g.document(); 

Наконец, нам нужно определить TokenQueue. TokenQueue не является строго необходимым, но я использовал его для удобства. Он должен иметь методы для получения лексерских токенов и методы вывода маркеров Antlr. Поэтому, если вы не используете собственные токены Antlr, вам нужно реализовать метод конвертирования в Antlr-token. Кроме того, TokenQueue должен реализовать ITokenSource.

Помните, что очень важно правильно установить переменные токена. Первоначально у меня были некоторые проблемы, потому что я просчитывал CharPositionInLine. Если эти переменные установлены неправильно, то анализатор может выйти из строя. Кроме того, нормальный канал (не скрытый) равен 0.

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

+0

хорошая работа, как вы обрабатывали файл .tokens? Я пытаюсь сделать что-то подобное, кроме использования pygments lexers – Naveen

+0

@Naveen Я ничего не помню, чтобы что-либо делать с файлом .tokens. – luiscubal

+0

Я получил ваш метод для работы с питоном. Другие использовали с jflex и stax. Я опубликовал простой пример в github: https://github.com/tinku99/antlr-pygments – Naveen