Estou escrevendo um analisador para uma linguagem de marcação que eu criei (escrevendo em python, mas isso não é realmente relevante para essa pergunta - na verdade, se isso parece uma má idéia, eu adoraria uma sugestão para um caminho melhor) .
Estou lendo sobre analisadores aqui: http://www.ferg.org/parsing/index.html e estou trabalhando para escrever o lexer que, se entender corretamente, deve dividir o conteúdo em tokens. O que estou tendo problemas para entender é quais tipos de token devo usar ou como criá-los. Por exemplo, os tipos de token no exemplo ao qual vinculei são:
- CORDA
- IDENTIFICADOR
- NÚMERO
- WHITESPACE
- COMENTE
- EOF
- Muitos símbolos como {e (contam como seu próprio tipo de token
O problema que estou tendo é que os tipos de token mais gerais parecem um pouco arbitrários para mim. Por exemplo, por que STRING é seu próprio tipo de token separado vs. IDENTIFIER. Uma sequência pode ser representada como STRING_START + (IDENTIFIER | WHITESPACE) + STRING_START.
Isso também pode ter a ver com as dificuldades do meu idioma. Por exemplo, declarações de variáveis são gravadas {var-name var value}
e implementadas com {var-name}
. Parece '{'
e '}'
devem ser seus próprios tokens, mas são os tipos de tokens elegíveis para VAR_NAME e VAR_VALUE, ou ambos se enquadram no IDENTIFIER? Além disso, o VAR_VALUE pode realmente conter espaço em branco. O espaço em branco depois var-name
é usado para significar o início do valor na declaração. Qualquer outro espaço em branco faz parte do valor. Esse espaço em branco se torna seu próprio token? Espaço em branco só tem esse significado neste contexto. Além disso, {
pode não ser o início de uma declaração de variável. Depende do contexto (existe essa palavra novamente!). {:
inicia uma declaração de nome e{
pode até ser usado como parte de algum valor.
Minha linguagem é semelhante ao Python, pois os blocos são criados com recuo. Eu estava lendo sobre como Python usa o lexer para criar TRAVESSÃO e fichas DEDENT (que servem mais ou menos como o que {
e }
iria fazer em um monte de outras línguas). O Python afirma ser livre de contexto, o que significa para mim que pelo menos o lexer não deve se preocupar com o local no fluxo ao criar tokens. Como o lexer do Python sabe que está construindo um token INDENT de um comprimento específico sem conhecer os caracteres anteriores (por exemplo, que a linha anterior era uma nova linha, então comece a criar os espaços para o INDENT)? Eu pergunto porque preciso saber disso também.
Minha pergunta final é a mais estúpida: por que um lexer é necessário? Parece-me que o analisador poderia ir caracter por caracter e descobrir onde está e o que espera. O lexer acrescenta o benefício da simplicidade?