J'écris un analyseur pour un langage de balisage que j'ai créé (écrit en python, mais ce n'est pas vraiment pertinent pour cette question - en fait, si cela semble être une mauvaise idée, j'aimerais une suggestion pour un meilleur chemin) .
Je lis sur les analyseurs ici: http://www.ferg.org/parsing/index.html , et je travaille sur l'écriture du lexer qui devrait, si je comprends bien, diviser le contenu en jetons. Ce que j'ai du mal à comprendre, c'est quels types de jetons je dois utiliser ou comment les créer. Par exemple, les types de jetons dans l'exemple auquel j'ai lié sont:
- CHAÎNE
- IDENTIFICATEUR
- NOMBRE
- WHITESPACE
- COMMENTAIRE
- EOF
- De nombreux symboles tels que {et (comptent comme leur propre type de jeton
Le problème que j'ai, c'est que les types de jetons plus généraux me semblent un peu arbitraires. Par exemple, pourquoi STRING a-t-il son propre type de jeton distinct par rapport à IDENTIFIER. Une chaîne peut être représentée par STRING_START + (IDENTIFIER | WHITESPACE) + STRING_START.
Cela peut aussi avoir à voir avec les difficultés de ma langue. Par exemple, les déclarations de variables sont écrites en tant que {var-name var value}
et déployées avec {var-name}
. Il semble '{'
et '}'
devraient être leurs propres jetons, mais les types de jetons VAR_NAME et VAR_VALUE sont-ils éligibles, ou ces deux tomberaient-ils sous IDENTIFIER? De plus, le VAR_VALUE peut contenir des espaces. L'espace après var-name
est utilisé pour signifier le début de la valeur dans la déclaration. Tout autre espace fait partie de la valeur. Cet espace blanc devient-il son propre jeton? L'espace blanc n'a cette signification que dans ce contexte. De plus, ce {
n'est peut-être pas le début d'une déclaration de variable .. cela dépend du contexte (il y a encore ce mot!). {:
démarre une déclaration de nom, et{
peut même être utilisé dans le cadre d'une certaine valeur.
Mon langage est similaire à Python dans la mesure où les blocs sont créés avec indentation. Je lisais sur la façon dont Python utilise le lexer pour créer des jetons INDENT et DEDENT (qui servent plus ou moins comme quoi {
et }
feraient dans beaucoup d'autres langues). Python prétend être sans contexte, ce qui signifie pour moi qu'au moins le lexer ne devrait pas se soucier de l'endroit où il se trouve dans le flux lors de la création de jetons. Comment le lexeur de Python sait-il qu'il construit un jeton INDENT d'une longueur spécifique sans connaître les caractères précédents (par exemple, que la ligne précédente était une nouvelle ligne, alors commencez à créer les espaces pour INDENT)? Je demande parce que j'ai besoin de le savoir aussi.
Ma dernière question est la plus stupide: pourquoi un lexer est-il même nécessaire? Il me semble que l'analyseur pourrait aller caractère par caractère et déterminer où il se trouve et ce qu'il attend. Le lexer ajoute-t-il l'avantage de la simplicité?