Pegjs: Forum ou chat ? Passer des valeurs vers le bas / faire apparaître des valeurs ?

Créé le 23 mars 2017  ·  7Commentaires  ·  Source: pegjs/pegjs

pegjs est simple et puissant. Je l'aime! J'ai quelques questions qui ne sont pas abordées dans la doc :

J'analyse ceci, ce qui fonctionne, mais la règle semble maladroite :

f = x => x * x

Si je le délègue pour dire Opérateur, il n'y a aucun moyen de transmettre des valeurs. Si je crée des ValuesOperators et ou = et =>, c'est un peu plus propre, mais au niveau supérieur, j'ai encore besoin de vérifier lequel c'était. Dans l'exemple JavaScript, je vois l'utilisation de { type: "Literal", value: ... }. Est-ce le meilleur moyen de retransmettre l'information ?

  = values:Values body:(_ "=>" _ Expression)? assign:(_ "=" _ Expression)? {
      if (body && body.length > 0) {
        return new Function(values, body[3]);
      } else if (assign) {
        return new Assignment(values, assign[3]);
      } else {
        return values;
      }
    }

Merci!
Mike

Commentaire le plus utile

Je supposais que ne pas revenir en arrière et être gourmand signifiait que vous deviez travailler avec "où que vous soyez actuellement", mais ce n'est pas le cas. Yay!

Greedy veut simplement dire que s'il trouve une correspondance, il la prendra, n'est-ce pas ? Mais si la règle entière ne correspond pas, elle recommencera depuis le début lors du prochain match. Cela rend les choses beaucoup plus faciles que la façon dont j'essayais de le faire au départ.

x, y = 2 + 3.foo + "foo", 5 * 2

C'est assez facile lorsque l'affectation peut être mise en correspondance séparément d'une expression régulière, etc.

  = Assignment
  / Expression

Assignment
  = vars:Variables _ "=" _ expr:Expression

Variables
  = head:Identifier tail:(_ "," _ Identifier)*

...

Tous les 7 commentaires

En grammaire, il est essentiel de comprendre les règles. Et vous ne fournissez que des sous .. ce n'est pas clair pour moi, comment cela peut-il être clair à la machine?
Les grammaires LALR sont très difficiles à écrire mais plus faciles que LR et plus faciles que LL..
La grammaire PEG est facile à écrire mais plus difficile à écrire efficacement.
Êtes-vous sûr d'utiliser le bon jouet ? Si vous avez une bonne grammaire PEG, vous devriez être capable de créer un transpiler ou d'interpréter aussi facilement que d'interpréter vos règles.

Connaissez-vous le boxing/unboxing dans les machines virtuelles ?

Comment pouvez-vous avoir values sur le côté gauche du devoir ? parce que vous avez ceci : body:(_ "=>" _ Expression)? terminé par ?

que signifie values dans votre grammaire ? Savez-vous ce qu'est la valeur L ?

Vous devez garder votre grammaire sémantiquement proche. C'est difficile avec PEG dans certains cas. { type: "Literal", value: ... } est exactement ce dont vous avez besoin dans AST. Regardez sur http://astexplorer.net/ à quoi cela peut ressembler

Je viens juste de commencer à l'utiliser pour expérimenter, alors oui, certains noms sont incorrects :) J'ai écrit quelques analyseurs syntaxiques LL(1) simples, mais cela fait longtemps. Je suis juste curieux de savoir quelle est la meilleure façon de gérer les décisions. Je vais simplifier pour cette syntaxe :

a = b
ou
x => x * x

Est-il plus approprié de faire quelque chose comme ça?

AffectationOuFonction
= ident:Identifier Operator:IdentOperator {
if (operator.type === "Fonction") {
...
}

IdentOperator
= "=" !">" { return { type : "Affectation" ; } }
/ "=>" { ... }

Pour info, "valeurs" était un terme que j'avais l'habitude de désigner comme une liste d'éléments - ce seraient des valeurs si elles étaient utilisées comme un tuple, mais des variables si elles étaient utilisées pour définir les arguments de la fonction. Par exemple (2 + 3).

Merci pour votre temps!

@mikeustin C'est à toi :-)

Écrire des grammaires est une question de réductions . Le plus haut est la déclaration . C'est comme la phrase, vous savez, vous avez des grammaires LL :-)

Il est de votre responsabilité de définir la grammaire dans le sens (désolé j'ai du mal avec l'anglais :-D parfois)

Comment voulez-vous traiter AssignmentOrFunction ? C'est fondamentalement la même que l' instruction dans de nombreuses langues, mais peut également être une valeur R.
D'un autre côté

    = "=" !">" { return { type: "Assignment"; } }
    / "=>" { ... }

peut être mieux écrit comme

    = "=>" { ... }
    / "=" { return { type: "Assignment"; } }

Peut-être que je me trompe... mais on dirait que vous cassez votre phrase en un fragment pas si important. Sans contexte, ce que vous évaluez n'est pas vraiment important.

Les PEG sont vraiment difficiles à écrire car vous pouvez facilement écrire des règles inaccessibles ou vous pouvez écrire des règles qui voleront votre phrase et les évalueront de manière incorrecte, donc si vous êtes débutant, vous devriez avoir des phrases à gauche et des AST obligatoires à droite tout le temps, dix fois plus de tests automatisés que de règles de grammaire. Croyez-moi, vous changez une règle et l'ensemble de votre analyseur se brisera.

Et bien sûr, vous devriez jouer avec, écrire quelque chose, encore et encore.. Il n'est pas anodin d'écrire une calculatrice d'expression efficace avec PEG, notez plusieurs niveaux de priorité.

Vous ne me donnez pas plus de contexte dans votre question, il est donc très difficile de deviner ce que vous voulez vraiment construire mais je suppose que vous devriez jouer davantage avec les grammaires, il y a AntLR , un excellent outil pour apprendre, GoldParser (LALR) (mon premier jouet :-) ), quelques analyseurs de la vieille école qui sont bien testés, les plus efficaces mais divisés en tokenizer/parser (anciens lex et yacc, nouveaux flex et bison), de nombreux ports d'entre eux..

PEG semble le plus simple. Ça l'est vraiment. Mais ce sera toujours le plus dangereux...

Merci beaucoup! Oh, j'ai trouvé le groupe Google pour pegjs, mais je ne l'ai pas remarqué car il se trouvait dans la section développement. Si j'ai d'autres questions, je vais certainement y aller à la place.

Oui, l'affectation "x = y" est une _instruction_, mais "x => x * x" peut faire partie d'une _expression_, ainsi que "x == y", etc. "=" est un cas particulier, et donc est "=>" dans le sens où ce ne sont pas des opérateurs réguliers. Je vais pratiquer plus et regarder de plus près les exemples. J'aimerais qu'il y ait des exemples plus grands que la calculatrice, mais plus petits que les autres exemples. Peut-être que si je progresse ça peut être un exemple :)

Pour mon projet, j'aimerais écrire un langage simple à transpiler en JS. Les bases sont des méthodes externes à portée lexicale (pas de patch de singe, comme Dylan ou CLOS mais sans multiméthodes), des arguments de mot-clé, des ADT, peut-être même un typage statique facultatif. "Simple" signifie simplement que tout fonctionne ensemble et qu'il n'y a qu'une seule façon de faire quelque chose. Faire quelque chose de simple peut être _difficile_.

De plus, il existe des bibliothèques comme adt et multimethods qui pourraient bénéficier de la syntaxe native. Ceux-ci pourraient en fait être atteints avec sweet , mais sweet ne peut qu'étendre JS, pas le rendre plus simple. TypeScript a des options telles que "--strictNullChecks" et prend en charge les types d'union en ligne, mais encore une fois, il étend JS de sorte qu'il laisse toujours toutes les mauvaises choses là (coercitions implicites, "+" pour la concaténation de chaînes, levage de portée, etc.).

Encore une fois, merci pour toute l'aide!
Mike

Je supposais que ne pas revenir en arrière et être gourmand signifiait que vous deviez travailler avec "où que vous soyez actuellement", mais ce n'est pas le cas. Yay!

Greedy veut simplement dire que s'il trouve une correspondance, il la prendra, n'est-ce pas ? Mais si la règle entière ne correspond pas, elle recommencera depuis le début lors du prochain match. Cela rend les choses beaucoup plus faciles que la façon dont j'essayais de le faire au départ.

x, y = 2 + 3.foo + "foo", 5 * 2

C'est assez facile lorsque l'affectation peut être mise en correspondance séparément d'une expression régulière, etc.

  = Assignment
  / Expression

Assignment
  = vars:Variables _ "=" _ expr:Expression

Variables
  = head:Identifier tail:(_ "," _ Identifier)*

...

Les PEG choix ordonné, ce qui signifie que le premier motif à correspondre dans une expression correspondra automatiquement. L'exemple de @langpavel est un bon moyen d'exprimer une préférence pour => rapport à = . Vous voudrez peut-être réfléchir davantage à ce qu'une expression peut être en termes de "une de ces choses" au lieu de "prendre tout ce texte qui pourrait être une expression et le découvrir plus tard"

  = FunctionExpression
  / Assignment
  / Value

Pour démontrer, j'ai créé une grammaire de test avec laquelle vous pouvez jouer. C'est un peu bruyant mais j'ai essayé de rester assez simple, en ignorant certaines choses comme autoriser des espaces et des opérateurs supplémentaires. Notez le bloc Expression où la magie opère. Aussi, j'ai utilisé des choses comme SubExpression et ExpressionList comme moyens de gérer les "beaucoup de ces" situations ; ce modèle fonctionne bien pour moi en gardant les séparateurs de liste et les éléments séparés.

Dans chaque cas, j'essaie de garder la grammaire simple en ayant un élément pour chaque type de correspondance. Il y a une certaine redondance car je pourrais la réécrire de telle sorte que nous ayons une grande séquence de correspondance avec toutes les combinaisons possibles, mais c'est difficile à suivre et à raisonner et laisse une ambiguïté ouverte que les PEG peuvent éliminer avec un choix ordonné. J'espère que ça aide.

Je vais jeter un œil à la grammaire du test, merci ! Il est utile de voir un sous-ensemble minimal d'un langage car la grammaire JavaScript est assez volumineuse.

@dmsnell J'ai beaucoup appris ces derniers temps en supprimant des règles et en en ajoutant quelques nouvelles à la grammaire JavaScript, vous pouvez voir les dernières ici : impulse.pegjs . J'ai supprimé la syntaxe élision [,,], certains opérateurs, expressions de séquence, etc. et ajouté la syntaxe de tuple (1, 2) et la syntaxe de plage 1..5. Les nombres à virgule flottante nécessitent une décimale des deux côtés pour faciliter l'analyse des plages littérales.

J'ai travaillé sur une grande partie du runtime ces derniers temps, mais je veux revenir à l'analyseur pour réellement émettre du JavaScript. Je suis entre deux boulots donc j'ai un peu de temps libre :) Quelques idées pour un dialecte nettoyé de JavaScript avec des méthodes d'extension, des paramètres nommés, des traits et des mixins, une surcharge d'opérateur et une syntaxe de tuple et de plage littéraux.

Merci encore!
Mike

Cette page vous a été utile?
0 / 5 - 0 notes