Pegjs: Forum oder Chat? Werte nach unten übergeben / Werte nach oben knallen?

Erstellt am 23. März 2017  ·  7Kommentare  ·  Quelle: pegjs/pegjs

pegjs ist einfach und leistungsstark. Ich liebe es! Ich habe ein paar Fragen, die in den Dokumenten nicht behandelt werden:

Ich analysiere das, was funktioniert, aber die Regel scheint umständlich:

f = x => x * x

Wenn ich es delegiere, Operator zu sagen, gibt es keine Möglichkeit, Werte weiterzugeben. Wenn ich ValuesOperators und oder = und => erstelle, ist es etwas sauberer, aber auf der obersten Ebene muss ich noch überprüfen, welches es war. Im JavaScript-Beispiel sehe ich die Verwendung von { type: "Literal", value: ... }. Ist das der beste Weg, um die Informationen zurückzugeben?

  = 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;
      }
    }

Vielen Dank!
Mike

Hilfreichster Kommentar

Ich war davon ausgegangen, dass kein Zurückverfolgen und Gier bedeutet, dass Sie mit "wo immer Sie gerade sind" arbeiten müssen, aber das ist nicht der Fall. Yay!

Gierig bedeutet nur, dass es, wenn es eine Übereinstimmung findet, es annehmen wird, richtig? Wenn die gesamte Regel jedoch nicht übereinstimmt, beginnt sie im nächsten Match von vorne. Das macht es viel einfacher, als ich es zuerst versucht habe.

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

Dies ist ziemlich einfach, wenn die Zuweisung getrennt von einem regulären Ausdruck usw. abgeglichen werden kann.

  = Assignment
  / Expression

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

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

...

Alle 7 Kommentare

In Grammatiken ist es wichtig, Regeln zu verstehen. Und du stellst nur unter .. das ist mir nicht klar, wie kann man das maschinell klar machen?
LALR-Grammatiken sind sehr schwer zu schreiben, aber einfacher als LR und einfacher als LL.
PEG-Grammatik ist einfach zu schreiben, aber am schwierigsten effizient zu schreiben.
Sind Sie sicher, dass Sie das richtige Spielzeug verwenden ? Wenn Sie eine gute PEG-Grammatik haben, sollten Sie in der Lage sein, einen Transpiler zu erstellen oder genauso einfach zu interpretieren wie Ihre Regeln zu interpretieren.

Kennen Sie Boxen/Unboxing in virtuellen Maschinen?

Wie können Sie values auf der linken Seite der Aufgabe haben? weil Sie folgendes haben: body:(_ "=>" _ Expression)? endete mit ?

Was sind values in Ihrer Grammatik? Wissen Sie, was der L-Wert ist ?

Sie müssen Ihre Grammatik semantisch eng halten. In manchen Fällen ist es mit PEG schwierig. { type: "Literal", value: ... } ist genau das, was Sie in AST brauchen. Schau auf http://astexplorer.net/ wie es aussehen kann

Ich habe gerade angefangen, es zum Experimentieren zu verwenden, also ja, einige der Namen sind falsch :) Ich habe ein paar einfache LL(1)-Parser geschrieben, aber es ist eine Weile her. Ich bin nur gespannt, wie man mit Entscheidungen am besten umgeht. Ich werde für diese Syntax vereinfachen:

a = b
oder
x => x * x

Ist es angemessener, so etwas zu tun?

ZuweisungOrFunktion
= ident:Identifier- Operator:IdentOperator {
if (operator.type === "Funktion") {
...
}

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

Zu Ihrer Information, "Werte" war ein Begriff, den ich verwendet habe, um eine Liste von Elementen zu bedeuten - sie wären Werte, wenn sie als Tupel verwendet werden, aber Variablen, wenn sie verwendet werden, um die Funktionsargumente zu definieren. Zum Beispiel (2 + 3).

Vielen Dank für Ihre Zeit!

@mikeaustin Es liegt an dir :-)

Beim Schreiben von Grammatiken dreht sich alles um Kürzungen . An oberster Stelle steht die Aussage . Es ist wie ein Satz, weißt du, du hast LL-Grammatiken :-)

Es liegt in Ihrer Verantwortung, Grammatik im Sinn zu definieren (sorry, ich habe manchmal Probleme mit Englisch :-D)

Wie möchten Sie AssignmentOrFunction verarbeiten? Dies entspricht im Grunde der Aussage in vielen Sprachen, kann aber auch ein R-Wert sein.
Auf der anderen Seite

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

kann besser geschrieben werden als

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

Kann sein, dass ich falsch liege.. aber das sieht so aus, als ob Sie Ihren Satz in ein nicht so wichtiges Fragment unterbrechen. Ohne Kontext ist es nicht wirklich wichtig, was man das bewertet..

PEGs sind wirklich schwer zu schreiben, weil Sie leicht unerreichbare Regeln schreiben können oder Regeln schreiben können, die Ihren Satz stehlen und falsch bewerten. Wenn Sie also Anfänger sind, sollten Sie die ganze Zeit Sätze links und erforderliche ASTs rechts haben, zehn mal mehr automatisierte Tests als Grammatikregeln. Vertrauen Sie mir, Sie ändern eine Regel und Ihr gesamter Parser wird brechen.

Und natürlich sollten Sie immer wieder damit spielen, etwas schreiben.

Sie geben mir in Ihrer Frage keinen weiteren Kontext, daher ist es sehr schwer zu erraten, was Sie wirklich bauen möchten, aber ich kann mir vorstellen , dass Sie mehr mit Grammatiken spielen sollten. Es gibt

PEG sieht am einfachsten aus. Ist es wirklich. Aber am gefährlichsten wird es immer sein...

Vielen Dank! Oh, ich habe die Google-Gruppe für pegjs gefunden, aber nicht bemerkt, weil sie sich im Entwicklungsbereich befand. Wenn ich andere Fragen habe, gehe ich auf jeden Fall dorthin.

Ja, die Zuweisung "x = y" ist eine _Anweisung_, aber "x => x * x" kann Teil eines _Ausdrucks_ sein, sowie "x == y" usw. "=" ist ein Sonderfall, und so ist "=>" in dem Sinne, dass sie keine regulären Operatoren sind. Ich werde mehr üben und mir die Beispiele genauer ansehen. Ich wünschte, es gäbe Beispiele, die größer wären als der Taschenrechner, aber kleiner als die anderen Beispiele. Vielleicht kann es ein Beispiel sein, wenn ich Fortschritte mache :)

Für mein Projekt möchte ich eine einfache Sprache schreiben, um sie in JS zu transpilieren. Grundlagen sind externe Methoden mit lexikalischem Geltungsbereich (kein Monkey-Patching, wie Dylan oder CLOS, aber ohne Multimethoden), Schlüsselwortargumente, ADTs, vielleicht sogar optionale statische Typisierung. "Einfach" bedeutet einfach, dass alles zusammenpasst und es nur einen Weg gibt, etwas zu tun. Etwas Einfaches zu machen kann _schwer_ sein.

Außerdem gibt es Bibliotheken wie adt und multimethods , die von nativer Syntax profitieren könnten. Das könnte man eigentlich mit süß erreichen , aber süß kann JS nur erweitern, nicht einfacher machen. TypeScript hat Optionen wie "--strictNullChecks" und unterstützt Inline-Union-Typen, aber auch hier erweitert es JS, sodass all die schlechten Dinge noch vorhanden sind (implizite Zwänge, "+" für String-Verkettung, Bereichserweiterung usw.).

Nochmals vielen Dank für die ganze Hilfe!
Mike

Ich war davon ausgegangen, dass kein Zurückverfolgen und Gier bedeutet, dass Sie mit "wo immer Sie gerade sind" arbeiten müssen, aber das ist nicht der Fall. Yay!

Gierig bedeutet nur, dass es, wenn es eine Übereinstimmung findet, es annehmen wird, richtig? Wenn die gesamte Regel jedoch nicht übereinstimmt, beginnt sie im nächsten Match von vorne. Das macht es viel einfacher, als ich es zuerst versucht habe.

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

Dies ist ziemlich einfach, wenn die Zuweisung getrennt von einem regulären Ausdruck usw. abgeglichen werden kann.

  = Assignment
  / Expression

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

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

...

@mikeaustin PEGs haben eine geordnete Auswahl, was bedeutet, dass das erste Muster, das in einem Ausdruck übereinstimmt, automatisch übereinstimmt. Das Beispiel von => gegenüber = auszudrücken. Vielleicht möchten Sie mehr darüber nachdenken, was ein Ausdruck im Sinne von "eines dieser Dinge" sein kann, anstatt "den ganzen Text zu greifen, der ein Ausdruck sein könnte, und ihn später herausfinden".

  = FunctionExpression
  / Assignment
  / Value

Zur Veranschaulichung habe ich eine Testgrammatik erstellt, mit der Sie spielen können. Es ist ein bisschen laut, aber ich habe versucht, es ziemlich einfach zu halten und einige Dinge wie das Zulassen von zusätzlichem Leerraum und Operatoren zu ignorieren. Beachten Sie den Block Expression , in dem die Magie passiert. Außerdem habe ich Dinge wie SubExpression und ExpressionList , um mit den "vielen dieser" Situationen umzugehen; dieses Muster funktioniert gut für mich, um die Listentrennzeichen und Elemente getrennt zu halten.

In jedem Fall versuche ich, die Grammatik einfach zu halten, indem ich ein Element für jede Art von Übereinstimmung habe. Es gibt einige Redundanzen, weil ich es so umschreiben könnte, dass wir eine große Match-Sequenz mit allen möglichen Kombinationen haben, aber das ist schwer zu verfolgen und zu begründen und lässt Unklarheiten offen, die PEGs mit geordneter Auswahl beseitigen können. Ich hoffe es hilft.

Ich schaue mir die Testgrammatik an, danke! Es hilft, eine minimale Teilmenge einer Sprache zu sehen, da die JavaScript-Grammatik ziemlich groß ist.

@dmsnell Ich habe in letzter Zeit viel gelernt, impulse.pegjs . Ich habe Elisionssyntax [,,], einige Operatoren, Sequenzausdrücke usw. entfernt und Tupelsyntax (1, 2) und Bereichssyntax 1..5 hinzugefügt. Gleitkommazahlen erfordern eine Dezimalstelle auf beiden Seiten, um das Analysieren von Literalbereichen zu erleichtern.

Ich habe in letzter Zeit viel an der Laufzeit gearbeitet, möchte aber zum Parser zurückkehren, um tatsächlich JavaScript auszugeben. Ich bin zwischen den Jobs, also habe ich ein wenig Zeit :) Einige Ideen für einen aufgeräumten JavaScript-Dialekt mit Erweiterungsmethoden, benannten Parametern, Traits und Mixins, Operatorüberladung und literaler Tupel- und Bereichssyntax.

Danke noch einmal!
Mike

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

richb-hanover picture richb-hanover  ·  7Kommentare

futagoza picture futagoza  ·  6Kommentare

StoneCypher picture StoneCypher  ·  6Kommentare

futagoza picture futagoza  ·  13Kommentare

emmenko picture emmenko  ·  15Kommentare