Должен ли лексер различать строковые токены разных типов?
Я пишу нефритовый язык, который перейдет в HTML. Вот как выглядит определение тега:
section #mainWrapper .container
это переносится на:
<section id="mainWrapper" class="container">
Должен ли лексер различать класс и идентификатор или он должен только выплевывать специальные символы с именами?
Другими словами, должен ли массив токенов выглядеть так:
[
{type: 'tag', value: 'section'},
{type: 'id', value: 'mainWrapper'},
{type: 'class', value: 'container'}
]
а затем парсер просто собирает их в дерево
или лексер должен быть очень примитивным и возвращать только совпадающие строки, а затем синтаксический анализатор позаботится о их различении?
[
{type: 'name', value: 'section'},
{type: 'name', value: '#mainWrapper'},
{type: 'name', value: '.container'}
]
1 ответ
Как правило, токенизаторы не должны анализировать, а анализатор не должен токенизироваться.
В этом конкретном случае мне кажется маловероятным, чтобы каждое неаккуратное использование именного токена - такого как section
- обязательно будет tag
, Это более вероятно, что section
является тегом из-за его синтаксического контекста. Если токенизатор пытается пометить его как tag
Затем токенизер отслеживает синтаксический контекст, что означает, что он выполняет синтаксический анализ.
Сигилы .
а также #
менее четкие. Вы можете считать их односимвольными токенами (за синтаксисом которых будет следовать имя) или вы можете считать их первым символом строки специального типа. Некоторые вещи, которые могут повлиять на вас так или иначе:
Можно ли отделить символ от следующего имени пробелом? (
# mainWrapper
). Если так, то, вероятно, символ - это знак.Отличается ли лексическая форма класса или идентификатора от имени? Подумайте, например, об использовании специальных символов. Если вы не можете точно распознать объект, не зная, какой символ (если он есть) предшествовал ему, тогда его лучше рассматривать как один токен.
Есть ли другие способы представления
class
имена. Например, как вы представляете несколько классов? Некоторые возможности вне моей головы:#classA #classB #(classA classB) #"classA classB" class = "classA classB"
Если какой-либо из параметров, кроме первого, действителен, вам, вероятно, следует просто
#
знак Но правильная обработка строк в кавычках может создать другие проблемы. В частности, для этого может потребоваться повторная идентификация содержимого строкового литерала, что будет нарушением эвристики, которую парсеры не должны маркировать. К счастью, это не абсолютные правила; иногда необходима повторная компоновка. Но сведите это к минимуму.
Разделение на лексический и синтаксический анализ не должно быть смирительной рубашкой. Это метод организации кода, предназначенный для облегчения написания, понимания, отладки и документирования отдельных частей. Часто (но не всегда) случается, что разделение облегчает пользователям вашего языка понимание синтаксиса, что также важно. Но это не подходит для каждой задачи анализа, и точная граница является гибкой (но не пористой: вы можете поместить границу там, где она наиболее удобна, но после ее размещения не пытайтесь протолкнуть вещи через трещины).
Если вы обнаружите, что такое разделение задач слишком сложно для вашего проекта, вам следует либо пересмотреть свой языковой дизайн, либо попробовать выполнить анализ без сканирования.