Je termine ma grammaire ECMAScript 5.1 / JavaScript pour JavaCC . J'ai fait tous les tokens et productions selon les spécifications.
Maintenant, je suis confronté à une grande question que je ne sais pas comment résoudre.
JavaScript a cette belle caractéristique de l'insertion automatique du point-virgule:
Quelles sont les règles pour l'insertion automatique de point-virgule (ASI) de JavaScript?
- Empêcher le cache dans chaque demande de Dojo xhr sur la page
- Comment résoudre l'application Android Phonegap SyntaxError: Parse error? (Problème d'écran vide)
- Comment faire une requête sur le type d'objet dans dojo?
- La case à cocher dojo dGrid header pour sélectionner tout ne fonctionne pas
- Dojo TabContainer pas de style
Pour citer les spécifications , les règles sont les suivantes:
Il existe trois règles de base de l'insertion de point-virgule:
Lorsque, à mesure que le programme est analysé de gauche à droite, un jeton (appelé le jeton offensant) est détecté qui n'est autorisé par aucune production de la grammaire, puis un point-virgule est automatiquement inséré avant le jeton offensant si un ou plusieurs des éléments suivants Les conditions sont vraies:
- Le jeton offensant est séparé du jeton précédent par au moins un LineTerminator.
- Le jeton offensant est
}
.Lorsque, au fur et à mesure que le programme est analysé de gauche à droite, la fin du flux d'entrée des jetons est rencontrée et l'analyseur est incapable d'analyser le flux de jeton d'entrée en tant que programme ECMAScript complet unique, puis un point-virgule est automatiquement inséré à la fin de Le flux d'entrée.
Lorsque, à mesure que le programme est analysé de gauche à droite, on trouve un jeton autorisé par une certaine production de la grammaire, mais la production est une production restreinte et le jeton serait le premier jeton pour un terminal ou un non terminal immédiatement après l'annotation
[no LineTerminator here]
dans la production restreinte (et donc un tel jeton s'appelle un jeton restreint), et le jeton restreint est séparé du jeton précédent par au moins unLineTerminator
, puis un point-virgule est automatiquement inséré avant le jeton restreint.Cependant, il existe une condition de substitution supplémentaire sur les règles précédentes: un point-virgule n'est jamais inséré automatiquement si le point-virgule serait ensuite analysé comme une instruction vide ou si ce point-virgule deviendrait l'un des deux points-virgules dans l'en-tête d'une déclaration for (voir 12.6.3 ).
Comment puis-je implémenter cela avec JavaCC?
La chose ferme à une réponse que j'ai trouvée jusqu'à présent est cette grammaire de Dojo toolkit qui possède une partie insertSemiColon
appelée insertSemiColon
dédiée à la tâche. Mais je ne vois pas que cette méthode s'appelle n'importe où (ni dans la grammaire ni dans l'ensemble du code jslinker ).
Comment puis-je aborder ce problème avec JavaCC?
Voir aussi cette question:
Javascript grammaire et insertion automatique de semocolon
(Pas de réponse là-bas.)
Une question des commentaires:
Est-il correct de dire que les points-virgules ne doivent être insérés que si les points-virgules sont syntaxiquement autorisés?
Je pense qu'il serait correct de dire que les points-virgules ne doivent être insérés que si les points-virgules sont syntaxiquement requis .
La partie pertinente ici est §7.9:
7.9 Insertion automatique du point-virgule
Certaines instructions ECMAScript (instruction vide, instruction de variable, déclaration d'expression, déclaration de do-while, instruction de continuité, déclaration de rupture, instruction de retour et instruction de lancement) doivent être terminées avec des points-virgules. Ces points-virgules peuvent toujours apparaître explicitement dans le texte source. Pour plus de commodité, cependant, ces points-virgules peuvent être omises du texte source dans certaines situations. Ces situations sont décrites en disant que les points-virgules sont automatiquement insérés dans le flux de jetons de code source dans ces situations.
Prenons l'énoncé de return
par exemple:
ReturnStatement : return ; return [no LineTerminator here] Expression ;
Donc (de ma compréhension) syntaxiquement, le point-virgule est requis , non seulement autorisé (comme dans votre question).
Les 3 règles pour l'insertion de point-virgule se trouvent dans la section 7.9.1 de la norme ECMAScript 5.1
Je pense que les règles 1 et 2 de la norme peuvent être manipulées avec un aspect sémantique.
void PossiblyInsertedSemicolon() {} { LOOKAHEAD( {semicolonNeedsInserting()} ) {} | ";" }
Alors, quand faut-il insérer un point-virgule? Quand l'un d'eux est vrai
getToken(1).kind != SEMICOLON && getToken(0).endLine < getToken(1).beginLine
) Nous avons donc besoin
boolean semicolonNeedsInserting() { return (`getToken(1).kind != SEMICOLON && getToken(0).endLine < getToken(1).beginLine`) || getToken(1).kind == RBRACE || getToken(1).kind == EOF ; }
Cela prend en charge les règles 1 et 2 de la norme.
Pour la règle 3 (productions restreintes), comme mentionné dans ma réponse à cette question , vous pouvez faire ce qui suit
void returnStatement() {} { "return" [ // Parse an expression unless either the next token is a ";", "}" or EOF, or the next token is on another line. LOOKAHEAD( { getToken(1).kind != SEMICOLON && getToken(1).kind != RBRACE && getToken(1).kind != EOF && getToken(0).endLine == getToken(1).beginLine} ) Expression() ] PossiblyInsertedSemicolon() }