SomeToken {
#[rule("/*" & ??? & "*/")]
MultilineComment
}
С помощью . точки.
#[rule("/*" & . & "*/")] даёт mistmatch на "/* hello */"
Всё разобрался. Спасибо.
. матчит ровно один символ. Но я бы вообще не рекомендовал запихивать целые комментарии в отдельные токены. Мне кажется, разбор комментариев лучше оставить для синтаксического парсера.
Я пока плохо ориентируюсь в парсерной тематике. Сначала разберусь как работает ваш проект, потом попробую прикрутить его к своему скрипту, а потом уже думаю придёт понимание как выстраивать архитектуру парсера.
Макрос, определяющий правило разбора для лексического анализатора.
Сделал ещё хуже
Сделай лучше
Если по простому, то лексический анализ это один из этапов, который помогает компилятору «понять» что написано в файле с исходным кодом.
А как в синтаксическом анализаторе указать "любой символ"? На точку он ругается.
В синтаксическом анализаторе придётся перечислять все возможные варианты вручную. Примерно вот так: #[rule(terminals: ( $True | $False | $Query | $Dot | $Dot2 | $Assign | $Plus | $PlusAssign | $Minus | $MinusAssign | $Mul | $MulAssign | $Div | $DivAssign | $And | $Or | $Not | $BitAnd | $BitAndAssign | $BitOr | $BitOrAssign | $BitXor | $BitXorAssign | $BitRem | $BitRemAssign | $Lesser | $LesserOrEqual | $Greater | $GreaterOrEqual | $Equal | $NotEqual | $Ident | $Int | $Float )+)] Terminals { terminals: Vec<TokenRef> }, В этом моменте пока есть неудобство. Надеюсь, что не слишком критическое.
Как в таком случае распарсить комментарий // в синтаксическом анализаторе? Я думал это будет вот так: #[rule($CommentStart & (.) & LineBreak+)] LineComment {},
именно так, только лучше использовать * вместо +, потому что у тебя коммент может быть в конце файла
Ну, я вот у себя буквально так и сделал. Я сделал #[define Any = $A | $B ...], в котором перечислил все токены, кроме токенов коммента. И потом использовал его как #[comment] #[rule( $InlineComment & (Any | $MultilineCommentStart | $MultilineCommentEnd)* & $Linebreak? )] InlineComment, Так же не забудьте поставить #[comment] метку. Если такую метку поставить, то коммент будет парситься автоматически во всех правилах(кроме собственно комментов).
А вот такие вещи как лучше описывать правилами? { some_field = value SomeSubNode {} } Если объявить в качестве токена Id #[define(LOWERCASE_LETTER = ['a'..'z'])] #[define(UPPERCASE_LETTER = ['A'..'Z'])] #[define(LETTER = LOWERCASE_LETTER | UPPERCASE_LETTER)] enum Tokens { #[rule(LETTER+ & ['_']* & LETTER+)] Id, } То some_field и SomeSubNode будут начинаться с Id, а синтаксис не позволяет положить их в разные ноды. Я пошел по пути объявления дополнительного токена CapitalId, который в отличии от Id начинается с UPPERCASE_LETTER, на сколько этот путь соответствует духу lady?
вообще, когда я пытался делать "язык" с максимально простой грамматикой, я ввел кейворды let и call, и присваивание всегда делал через let, чтобы не заморачиваться с вот такими вещами
Разделить токены на два класса (с заглваной и не с заглавной) это я думаю правильный подход, если у вас семантически с точки зрения вашего языка это действительно разные виды идентификаторов, и они не могут пересекаться. В целом про LD нужно понимать такую вещь, что задача лексера и парсера построить нечто вроде того, что в Расте называется TokenTree. То есть последовательность токенов, неким образом разделённая на синтаксические группы. В Расте такое разделение проходит по скобочным выражениям. В вашем языке вы можете сделать немного более структурно сложное разделение, но в целом нужно понимать, что задача LD не сконструировать полностью весь синтаксис в виде конечного дерева, а просто сконструировать некий прототип дерева, который будет удобно анализировать руками.
Конкретно в этом случае не должно быть ни let ни call, ни других ключевых слов вначале ноды. Это особенность этого DSL. За references огромное спасибо, посмотрю как вы с таким работаете.
Обсуждают сегодня