[ << Scheme-Tutorium ] | [Anfang][Inhalt][Index] | [ Schnittstellen für Programmierer >> ] |
[ < Scheme in LilyPond ] | [ Nach oben : Scheme in LilyPond ] | [ LilyPond-Variablen > ] |
1.2.1 LilyPond Scheme-Syntax
Der Guile-Auswerter ist ein Teil von LilyPond, sodass Scheme also auch in normale LilyPond-Eingabedateien eingefügt werden kann. Es gibt mehrere Methoden, um Scheme in LilyPond zu integrieren.
Die einfachste Weise ist es, ein Rautenzeichen #
vor einem
Scheme-Ausdruck zu benutzen.
Die Eingabe von LilyPond ist in Zeichen und Ausdrücke gegliedert, so etwa wie die menschliche Sprache sich in Wörter und Sätze gliedert. LilyPond hat einen Lexer, der Zeichen erkennt (Zahlen, Zeichenketten, Scheme-Elemente, Tonhöhen usw.) und einen Parser, der die Syntax versteht, LilyPond-Grammatik. Wenn dann eine bestimmte Syntaxregel als zuständig erkannt wurde, werden die damit verknüpften Aktionen ausgeführt.
Die Rautenzeichenmethode (#
), mit der Scheme eingebettet werden kann,
passt sehr gut in dieses System. Wenn der Lexer ein Rautenzeichen sieht, ruft
er den Scheme-reader auf, um den ganzen Scheme-Ausdruck zu lesen (das kann eine
Variable, ein Ausdruck in Klammern oder verschiedene andere Sachen sein). Nachdem
der Scheme-Ausdruck gelesen wurde, wird er als Wert eines SCM_TOKEN
in der
Grammatik gespeichert. Wenn der Parser weiß, wie er diesen Wert benutzen kann,
ruft er Guile auf, um den Scheme-Ausdruck auszuwerten. Weil der Parser normalerweise
dem Lexer etwas voraus sein muss, ist die Trennung von Lesen und Auswerten zwischen
Lexer und Parser genau das richtige, um die Auswertung von LilyPond- und
Scheme-Ausdrücken synchron zu halten. Aus diesem Grund sollte das Rautenzeichen
zum Einbinden von Scheme immer benutzt werden, wenn es möglich ist.
Eine andere Möglichkeit, Scheme aufzurufen, ist die Benutzung des Dollarzeichens
($
) anstelle der Raute. In diesem Fall wertet LilyPond den Code sofort
aus, nachdem der Lexer ihn gelesen hat. Dabei wird der resultierende
Scheme-Ausdruckstyp geprüft und eine Tokentyp dafür ausgesucht (einer von mehreren
xxx_IDENTIFIER
in der Syntax). Wenn der Wert des Ausdrucks gültig ist
(der Guilde-Wert für *unspecified*
), dann wird nichts an den Parser
übergeben.
Das ist auch der gleiche Mechanismus, nach dem LilyPond funktioniert, wenn man eine Variable oder musikalische Funktion mit ihrer Bezeichnung ausruft, wie
in \Bezeichnung
, mit dem einzigen Unterschied, dass ihre Bezeichnung durch den
LilyPond-Lexer bestimmt wird, ohne den Scheme-reader einzubeziehen, und also
nur Variablen akzeptiert werden, die im aktuellen LilyPond-Modus gültig sind.
Die direkte Auswirkung von $
kann zu Überraschungen führen, siehe
Eingabe-Variablen und Scheme. Es bietet sich daher an, #
immer
zu benützen, wenn der Parser es unterstützt. Innerhalb von musikalischen
Ausdrücken werden Ausdrücke, die mit #
erstellt werden, tatsächlich
als Noten interpretiert. Sie werden jedoch nicht vor der Benutzung
kopiert. Wenn Sie Teil einer Struktur sind, die noch einmal benutzt werden
soll, muss man eventuell ly:music-deep-copy
explizit einsetzen.
Es gibt auch die Operatoren $@
und #@
, die eine „listentrennende“
Funktion aufweisen, indem sie alle Elemente einer Liste in den umgebenden
Kontext einfügen.
Jetzt wollen wir uns tatsächlichen Scheme-Code anschauen. Scheme-Prozeduren können in LilyPond-Eingabedateien definiert werden:
#(define (average a b c) (/ (+ a b c) 3))
LilyPond-Kommentare (%
oder %{ %}
) können innerhalb
von Scheme-Code nicht benutzt werden, nicht einmal in einer LilyPond-Eingabedatei,
weil der Guile-Interpreter und nicht der LilyPond-Parser den Scheme-Ausdruck
liest. Kommentare in Guile Scheme werden wie folgt notiert:
; Einzeiliges Kommentar #! Guile-Stil Blockkommentar (nicht schachtelbar) Diese Kommentare werden von Scheme-Programmierern selten benutzt und nie im Quellcode von LilyPond !#
Für den Rest dieses Abschnitts soll angenommen werden, dass die Daten in
einer LilyPond-Eingabedatei notiert werden sollen, sodass immer #
vor die Scheme-Ausdrücke gestellt wird.
Alle Scheme-Ausdrücke auf oberster Ebene in einer LilyPond-Eingabedatei
können in einen einzigen Scheme-Ausdruck zusammengefasst werden mit
begin
:
#(begin (define foo 0) (define bar 1))
[ << Scheme-Tutorium ] | [Anfang][Inhalt][Index] | [ Schnittstellen für Programmierer >> ] |
[ < Scheme in LilyPond ] | [ Nach oben : Scheme in LilyPond ] | [ LilyPond-Variablen > ] |