Как мне реализовать двухпроходный сканер с помощью Flex?
-
01-07-2019 - |
Вопрос
В качестве домашнего проекта я хотел бы попытаться реализовать базовый язык моего собственного дизайна, который можно использовать в качестве языка веб-сценариев.Запустить программу на C ++ как Apache CGI тривиально, поэтому реальная работа заключается в том, как проанализировать входной файл, содержащий некод (разметку HTML / CSS) и код на стороне сервера.
На моем курсе компиляции для старшекурсников мы использовали Гибкий и Бизон сгенерировать сканер и синтаксический анализатор для простого языка.Нам дали копию грамматики, и мы написали синтаксический анализатор, который перевел простой язык в простую сборку для виртуальной машины.Сканер flex маркирует входные данные и передает маркеры анализатору Bison.
Разница между этим и тем, что я хотел бы сделать, заключается в том, что, как и PHP, этот язык может иметь простую HTML-разметку и язык сценариев, чередующийся следующим образом:
<p>Hello,
<? echo "World ?>
</p>
Ошибаюсь ли я, предполагая, что было бы эффективно проанализировать входной файл следующим образом:
- Сканируйте входные данные до тех пор, пока не будет найден начальный тег скрипта ('
- Второй сканер маркирует раздел сценария на стороне сервера входного файла (из тега open:") и передает токен анализатору, которому нет необходимости знать о разметке в файле.
- Управление возвращается первому сканеру, который продолжает эту общую схему.
По сути, первый сканер различает только разметку (которая возвращается непосредственно в браузер без изменений) и код, который передается второму сканеру, который, в свою очередь, маркирует код и передает токены анализатору.
Если это нет надежный шаблон проектирования, как такие языки, как PHP, эффективно обрабатывают входные данные сканирования и синтаксический анализ кода?
Решение
Вы хотите посмотреть на начальные условия.Например:
"<?" { 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_, определенные вашим файлом yacc.
Другие советы
PHP не делает различий между сканированием и разметкой.Он просто выводит данные в буфер, когда находится в режиме разметки, а затем переключается на синтаксический анализ, когда находится в режиме кода.Вам не нужен двухпроходный сканер, и вы можете сделать это с помощью всего лишь одного гибкого лексера.
Если вас интересует, как работает сам PHP, загрузите исходный код (попробуйте исходный код PHP4, его намного проще понять).То, на что вы хотите посмотреть, находится в каталоге Zend, zend_language_scanner.l
.
Написав что-то подобное сам, я бы действительно рекомендовал переосмыслить использование маршрута Flex и Bison и выбрать что-нибудь современное, например Antlr.Это намного проще и понятнее (макросы, используемые в грамматике lex, становятся очень запутанными и их трудно читать), и у него есть встроенный отладчик (АнтлрВоркс) таким образом, вам не придется тратить часы на просмотр файлов отладки размером 3 мегабайта.Он также поддерживает множество языков (Java, c #, Си, Python, Actionscript) и содержит отличную книгу и очень хороший веб-сайт, который должен помочь вам начать работу в кратчайшие сроки.