[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: c#(+6 2)

From: David Kastrup
Subject: Re: c#(+6 2)
Date: Mon, 12 Mar 2018 09:25:36 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux)

Gianmaria Lari <address@hidden> writes:

> On 11 March 2018 at 10:58, David Kastrup <address@hidden> wrote:
>> Then Scheme expressions written using # in the middle of music are
>> expected to be music expressions.
>> If you want to insert an actual
>> duration, you need to write it preceded with $ so that it can have
>> different type (and trigger different syntactic rules).
>> But $8 is not a duration.  $(ly:make-duration 3 0) would be a duration.
> How does it work ?
> Originary I thought that before source compilation, there was a step where
> to replace scheme expressions with their evaluation, like a preprocessor;
> that's why I tried c#(+ 6 2). But ok, it's clear it doesn't work in this
> way.
> Is this handled by the lilypond parser that create a parse tree and then
> according position in the tree and # or $ it expects different types?
> Thank you, g.

>From the "Extending LilyPond" guide:

1.2.1 LilyPond Scheme syntax

The Guile interpreter is part of LilyPond, which means that Scheme can
be included in LilyPond input files.  There are several methods for
including Scheme in LilyPond.

   The simplest way is to use a hash mark ‘#’ before a Scheme

   Now LilyPond’s input is structured into tokens and expressions, much
like human language is structured into words and sentences.  LilyPond
has a lexer that recognizes tokens (literal numbers, strings, Scheme
elements, pitches and so on), and a parser that understands the syntax,
*note (lilypond-contributor)LilyPond grammar::.  Once it knows that a
particular syntax rule applies, it executes actions associated with it.

   The hash mark ‘#’ method of embedding Scheme is a natural fit for
this system.  Once the lexer sees a hash mark, it calls the Scheme
reader to read one full Scheme expression (this can be an identifier, an
expression enclosed in parentheses, or several other things).  After the
Scheme expression is read, it is stored away as the value for an
‘SCM_TOKEN’ in the grammar.  Once the parser knows how to make use of
this token, it calls Guile for evaluating the Scheme expression.  Since
the parser usually requires a bit of lookahead from the lexer to make
its parsing decisions, this separation of reading and evaluation between
lexer and parser is exactly what is needed to keep the execution of
LilyPond and Scheme expressions in sync.  For this reason, you should
use the hash mark ‘#’ for calling Scheme whenever this is feasible.

   Another way to call the Scheme interpreter from LilyPond is the use
of dollar ‘$’ instead of a hash mark for introducing Scheme expressions.
In this case, LilyPond evaluates the code right after the lexer has read
it.  It checks the resulting type of the Scheme expression and then
picks a token type (one of several ‘xxx_IDENTIFIER’ in the syntax) for
it.  It creates a _copy_ of the value and uses that for the value of the
token.  If the value of the expression is void (Guile’s value of
‘*unspecified*’), nothing at all is passed to the parser.

   This is, in fact, exactly the same mechanism that LilyPond employs
when you call any variable or music function by name, as ‘\name’, with
the only difference that the name is determined by the LilyPond lexer
without consulting the Scheme reader, and thus only variable names
consistent with the current LilyPond mode are accepted.

   The immediate action of ‘$’ can lead to surprises, see *note
Importing Scheme in LilyPond::.  Using ‘#’ where the parser supports it
is usually preferable.  Inside of music expressions, expressions created
using ‘#’ _are_ interpreted as music.  However, they are _not_ copied
before use.  If they are part of some structure that might still get
used, you may need to use ‘ly:music-deep-copy’ explicitly.

David Kastrup

reply via email to

[Prev in Thread] Current Thread [Next in Thread]