Как реализовать двухпроходный сканер с помощью Flex? - PullRequest
7 голосов
/ 19 сентября 2008

Как домашний проект, я хотел бы попытаться реализовать базовый язык моего собственного дизайна, который можно использовать в качестве языка веб-сценариев. Запуск программы на C ++ в виде Apache CGI тривиален, поэтому настоящая работа заключается в том, как разобрать входной файл, содержащий некодовый (разметка HTML / CSS) и серверный код.

В моем курсе по компиляции для студентов мы использовали Flex и Bison для создания сканера и анализатора для простого языка. Нам дали копию грамматики и написали анализатор, который переводил простой язык в простую сборку для виртуальной машины. Гибкий сканер токенизирует входные данные и передает токены анализатору Bison.

Разница между этим и тем, что я хотел бы сделать, заключается в том, что, подобно PHP, этот язык может иметь простую разметку HTML и язык сценариев с вкраплениями, как показано ниже:

<p>Hello,
<? echo "World ?>
</p>

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

  1. Сканирование ввода до тех пор, пока не будет найден начальный тег скрипта ('
  2. Второй сканер токенизирует секцию серверного скрипта входного файла (из открытого тега: '') и передает токен парсеру, который не должен знать о разметке в файле.
  3. Элемент управления возвращается к первому сканеру, который продолжает этот общий шаблон.

По сути, первый сканер различает только разметку (которая возвращается непосредственно в браузер без изменений) и код, который передается второму сканеру, который, в свою очередь, маркирует код и передает токены в анализатор.

Если это , а не сплошной шаблон проектирования, как языки, такие как PHP, эффективно справляются со сканированием ввода и парсинга кода?

Ответы [ 2 ]

6 голосов
/ 21 сентября 2008

Вы хотите посмотреть на стартовые условия. Например:

"<?"            { BEGIN (PHP); }
<PHP>[a-zA-Z]*  { return PHP_TOKEN; }
<PHP>">?"       { BEGIN (0); }
[a-zA-Z]*       { return HTML_TOKEN; }

Вы начинаете в состоянии 0, используйте макрос BEGIN для изменения состояний. Чтобы сопоставлять RE только в определенном состоянии, добавьте к RE префикс с именем состояния, заключенным в угловые скобки.

В приведенном выше примере "PHP" - это состояние. «PHP_TOKEN» и «HTML_TOKEN» - это _% token_s, определенные вашим файлом yacc.

2 голосов
/ 20 сентября 2008

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

Если вас интересует, как работает сам PHP, скачайте исходный код (попробуйте исходный код PHP4, это намного проще понять). То, что вы хотите посмотреть, находится в Zend Directory, zend_language_scanner.l.

Написав что-то похожее, я бы действительно порекомендовал переосмыслить маршрут Flex и Bison и пойти на что-то современное, например Antlr . Это намного проще, проще для понимания (макросы, используемые в лекс-грамматике, становятся очень запутанными и трудными для чтения) и имеют встроенный отладчик ( AntlrWorks ), поэтому вам не нужно тратить часы смотря на файлы отладки 3 мег. Он также поддерживает многие языки (Java, c #, C, Python, Actionscript) и имеет отличную книгу и очень хороший веб-сайт, который должен быть в состоянии быстро приступить к работе.

...