Pegjs: Wie werden Leerzeichen-Trennzeichen beibehalten?

Erstellt am 3. Okt. 2019  ·  6Kommentare  ·  Quelle: pegjs/pegjs

Problemtyp

  • Fehlerbericht : _no_
  • Funktionsanfrage: _nein_
  • Frage: _ja_
  • Kein Problem: _nein_

Voraussetzungen

  • Können Sie das Problem reproduzieren?: _ja_
  • Haben Sie die Repository-Probleme durchsucht?: _ja_
  • Hast du die Foren überprüft?: _ja_
  • Haben Sie eine Websuche durchgeführt (Google, Yahoo usw.)?: _ja_

Ich habe Mühe, den PEG.js-Parser dazu zu bringen, die ursprünglichen Leerzeichen der Gleichung beizubehalten.

Aktuelles Verhalten: 2 * 5 + SUM(1, 2, 3)

[
   "2",
   "*",
   "5",
   "+",
   "SUM",
   "(",
   [
      "1",
      ",",
      "2",
      ",",
      "3"
   ],
   ")"
]

Gewünschtes Verhalten : 2 * 5 + SUM(1, 2, 3)

[
   "2",
   " ",
   "*",
   " ",
   "5",
   " ",
   "+",
   " ",
   "SUM",
   "(",
   [
      "1",
      ",",
      " ",
      "2",
      ",",
      " ",
      "3"
   ],
   ")"
]

Grammatik zum Kopieren: https://pastebin.com/zpwqT6Uw
PEG.js-Playground https://pegjs.org/online

Was vermisse ich?

Hilfreichster Kommentar

@marek-baranowski Noch ein sanfter Ping :smiley_cat:

Außerdem habe ich ein PEG.js-Plugin pegjs-syntactic-actions geschrieben , um das Debuggen von Grammatiken zu erleichtern und speziell zu sehen, welche Zeichen von welcher Regel unabhängig von den Aktionen erfasst werden, was wahrscheinlich Ihr Problem hier ist, wie von @StoneCypher erklärt.

Die Begründung dieses Plugins ist: Ich finde es oft/manchmal schwierig, das globale Ergebnis zu verstehen, wenn es nicht das ist, was wir erwarten, weil es aus der Kombination vieler kleiner Aktionen resultiert und das Finden der Aktion, die sich schlecht/merkwürdig verhält, sein könnte zeitaufwendig. Mit diesem Plugin sehen wir, welche Regel welchen Charakter erfasst, und es gibt den Namen der Aktion an, auf die reagiert werden soll.

Alle 6 Kommentare

@futagoza tut mir unglaublich leid, Sie zu stören, aber es ist das erste Mal, dass ich mich mit PEG.js beschäftige, und dieses Problem ist für mich von entscheidender Bedeutung. Darf ich Sie um einen kleinen Hinweis bitten?

Mit freundlichen Grüßen,
Marek

Ich habe versucht, Ihre Grammatik durchzusehen (gestern und gerade), aber weil es wirklich schwer zu verstehen ist (abgesehen von den Namenskonventionen ist das Format ehrlich gesagt überall verstreut), hat es eine Weile gedauert, bis ich eine Lösung gefunden habe:

  1. Regeln, die Platz und Daten verbrauchen, geben ihn zurück (z. B. gibt const [left_space, cnst, right_space] zurück)
  2. Jede Regel/Aktion, die das Ergebnis übernimmt, muss etwa so aussehen: [].concat.apply([], con)

Trotzdem, um ehrlich zu sein, fühlt sich das für mich wie eine Hacky-Lösung an. Hast du einen Link zu einer Spezifikation oder so? Es wäre hilfreich zu wissen, welche Regeln ich ändern kann und welche nicht, um das gewünschte Ergebnis ohne die obige Hacky-Lösung zu erzielen.

Wenn nicht, solange Sie bereit sind, die Zeit zu investieren und die Grammatik aufzuräumen und einige Regeln umzubenennen (damit Sie leichter herausfinden können, was Sie wollen), versuche ich es gerne noch einmal 😉

@marek-baranowski - Entschuldigung, das habe ich erst jetzt gesehen. Hoffentlich ist dies noch nützlich für Sie

Wenn Sie die Bereiche behalten möchten, behandeln Sie sie einfach wie Matchable Content.

Es ist nicht wirklich klar, was genau Sie für zwei Leerzeichen wollen. Sie könnten entweder eine Zeichenfolge mit zwei Leerzeichen oder ein Array mit zwei Zeichenfolgen mit einem Leerzeichen haben. Normalerweise würde ich Ersteres erwarten, aber ... alles ist pro Charakter

Außerdem ... warum sollten Sie solche Streuzeichen wollen, außer für den Funktionsaufruf? Der Parser sollte diese für Sie zusammenfassen.

Ohnehin

Das hast du gefragt:

Document = Expression*

Whitespace
  = tx:[ \r\n]+ { return tx.join(''); }

Number
  = str:[0-9]+ { return str.join(''); }

Oper
  = '+'
  / '-'
  / '/'
  / '*'
  / ','

Label
  = l:[a-zA-Z]+ { return l.join(''); }

Parens 
  = '(' Whitespace? ex:Expression* Whitespace? ')' { return ex; }

Expression 
  = Number 
  / Oper
  / Whitespace
  / Label
  / Parens
  / [^()]+

image

Die Sache ist, ich bin nicht wirklich davon überzeugt, dass es wirklich das ist, was Sie wollen. Als Beispiel könnten Sie stattdessen die Zahlen und Operatoren analysieren und für jede eine standardisierte Knotenform zurückgeben:

Document = Expression*

Whitespace
  = tx:[ \r\n]+ { return { 
    ast: 'whitespace', value: tx.join('') 
  }; }

Number
  = str:[0-9]+ { return {
    ast: 'number', value: parseInt(str,10)
  }; }

Oper
  = '+' { return { ast: 'oper', value: 'add' }}
  / '-' { return { ast: 'oper', value: 'subtract' }}
  / '/' { return { ast: 'oper', value: 'divide' }}
  / '*' { return { ast: 'oper', value: 'multiply' }}
  / ',' { return { ast: 'oper', value: 'sequence' }}

Label
  = l:[a-zA-Z]+ { return { 
    ast: 'label', value: l.join('') 
  }; }

Parens 
  = '(' Whitespace? ex:Expression* Whitespace? ')' { 
    return { ast: 'parens', value: ex 
  }; }

Expression 
  = Number 
  / Oper
  / Whitespace
  / Label
  / Parens
  / [^()]+

Jetzt haben Sie immer noch Ihre Leerzeichen, aber Sie haben auch einen richtig geparsten Baum und müssen keinen Parser schreiben, um die Ausgabe Ihres Parsers zu parsen, und es ist jetzt auch kinderleicht, reguläre Funktionen wie Zeilennummern usw. hinzuzufügen

image

@marek-baranowski - Ich möchte die Größe dieses Issue-Trackers etwas reduzieren

Wenn Sie das oben Gesagte benötigen, würden Sie bitte in Betracht ziehen, dieses Problem zu schließen? Danke 😄

Wenn dies nicht der Fall ist, teilen Sie mir bitte den Grund mit, und ich werde es erneut versuchen

@marek-baranowski Noch ein sanfter Ping :smiley_cat:

Außerdem habe ich ein PEG.js-Plugin pegjs-syntactic-actions geschrieben , um das Debuggen von Grammatiken zu erleichtern und speziell zu sehen, welche Zeichen von welcher Regel unabhängig von den Aktionen erfasst werden, was wahrscheinlich Ihr Problem hier ist, wie von @StoneCypher erklärt.

Die Begründung dieses Plugins ist: Ich finde es oft/manchmal schwierig, das globale Ergebnis zu verstehen, wenn es nicht das ist, was wir erwarten, weil es aus der Kombination vieler kleiner Aktionen resultiert und das Finden der Aktion, die sich schlecht/merkwürdig verhält, sein könnte zeitaufwendig. Mit diesem Plugin sehen wir, welche Regel welchen Charakter erfasst, und es gibt den Namen der Aktion an, auf die reagiert werden soll.

oh wow, das ist wirklich ordentlich

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen