3 Stimmen

LALR-Grammatik, abschließende Kommas und mehrzeilige Listenzuweisung

Ich versuche, eine LALR-Grammatik für eine sehr einfache Sprache zu erstellen, die aus Zuweisungen besteht. Zum Beispiel:

foo = "bar"
bar = 42

Die Sprache sollte auch Listen von Werten verarbeiten, zum Beispiel:

foo = 1, 2, 3

Aber ich möchte auch Listen über mehrere Zeilen verarbeiten:

foo = 1, 2
      3, 4

Trailing Comma (für Einzelwerte und Flexibilität der Sprache):

foo = 1,
foo = 1, 2,

Und natürlich auch beides gleichzeitig:

foo = 1,
      2,
      3,

Ich bin in der Lage, eine Grammatik mit einer abschließenden Komma oder einer mehrzeiligen Liste zu schreiben, aber nicht für beides gleichzeitig.

Meine Grammatik sieht so aus:

content : content '\n'
        : content assignment
        | 

assignment : NAME '=' value
           | NAME '=' list

value : TEXT
      | NUMBER

list : ???

Hinweis: Ich benötige das '\n' in der Grammatik, um folgenden Code zu verhindern:

foo
=
"bar"

Vielen Dank im Voraus,

Antoine.

2voto

Kaz Punkte 51547

Es sieht so aus, als ob Ihre Konfigurationssprache im Wesentlichen frei formatiert ist. Ich würde vergessen, newline zu einem Token in der Grammatik zu machen. Wenn Sie die newline-Beschränkungen wünschen, können Sie es als einige lexikalische Bindungsregeln hacken, wodurch der Parser eine kleine API verwendet, die dem Lexer hinzugefügt wird, um den Lexer darüber zu informieren, wo er sich in der Grammatik befindet, und der Lexer entscheiden kann, ob er Newlines akzeptiert oder mit einem Fehler ablehnt.

Versuchen Sie diese Grammatik.

%token NAME NUMBER TEXT

%%

config_file : assignments
            | /* leer */
            ;

assignments : assignment
            | assignments assignment
            ;

assignment : NAME '=' values comma_opt

comma_opt : ',' | /* leer */;

values : value
       | values ',' value
       ;

value : NUMBER | TEXT ;

Es baut für mich ohne Konflikte. Ich habe es nicht ausgeführt, aber beim flüchtigen Lesen von y.output sehen die Übergänge vernünftig aus.

Diese Grammatik erlaubt natürlich

foo = 1, 2, 3, bar = 4, 5, 6 xyzzy = 7 answer = 42

ohne zusätzliche Kommunikation mit dem Lexer.

Ihre Beschränkungen bedeuten, dass Zeilenumbrüche nur in den Werten erlaubt sind. Zwei NAME-Token dürfen niemals auf derselben Zeile erscheinen, und das = muss auf derselben Zeile wie der vorhergehende NAME erscheinen (und wahrscheinlich muss auch der erste Wert).

Im Grunde genommen kann der Parser, wenn er den ersten Wert durchsucht, dem Lexer "Werte werden jetzt gescannt, schalten Sie die Zulassung von Zeilenumbrüchen ein" sagen. Und dann, wenn comma_opt reduziert wird, kann dies wieder ausgeschaltet werden. Wenn comma_opt reduziert wird, hat der Lexer möglicherweise bereits das NAME-Token der nächsten Zuweisung gelesen, aber er kann überprüfen, ob dies auf einer anderen Zeile als der vorherigen NAME auftritt. Sie werden wollen, dass Ihr Lexer in jedem Fall eine genaue Zeilenzählung behält.

0voto

aquavitae Punkte 15648

Ich habe nicht wirklich viel Erfahrung damit, aber würde das funktionieren?

listvalue : Wert ,
          | Wert '\n'
          | Wert , '\n'

list : listvalue list

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X