]> git.donarmstrong.com Git - lilypond.git/blob - lily/parser.yy
Eliminate MARKUP_IDENTIFIER and MARKUPLIST_IDENTIFIER
[lilypond.git] / lily / parser.yy
1 /* -*- mode: c++; c-file-style: "linux"; indent-tabs-mode: t -*- */
2 /*
3   This file is part of LilyPond, the GNU music typesetter.
4
5   Copyright (C) 1997--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
6                  Jan Nieuwenhuizen <janneke@gnu.org>
7
8   LilyPond is free software: you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation, either version 3 of the License, or
11   (at your option) any later version.
12
13   LilyPond is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /* Mode and indentation are at best a rough approximation based on TAB
23  * formatting (reasonable for compatibility with unspecific editor
24  * modes as Bison modes are hard to find) and need manual correction
25  * frequently.  Without a reasonably dependable way of formatting a
26  * Bison file sensibly, there is little point in trying to fix the
27  * inconsistent state of indentation.
28  */
29
30 %{
31
32 #define yyerror Lily_parser::parser_error
33
34 /* We use custom location type: Input objects */
35 #define YYLTYPE Input
36 #define YYSTYPE SCM
37 #define YYLLOC_DEFAULT(Current,Rhs,N) \
38         ((Current).set_location ((Rhs)[1], (Rhs)[N]))
39
40 #define YYPRINT(file, type, value)                                      \
41         do {                                                            \
42                 if (scm_is_eq (value, SCM_UNSPECIFIED))                 \
43                         break;                                          \
44                 char *p = scm_to_locale_string                          \
45                         (scm_simple_format (SCM_BOOL_F,                 \
46                                             scm_from_locale_string ("~S"), \
47                                             scm_list_1 (value)));       \
48                 fputs (p, file);                                        \
49                 free (p);                                               \
50         } while (0)
51
52 %}
53
54 %parse-param {Lily_parser *parser}
55 %parse-param {SCM *retval}
56 %lex-param {Lily_parser *parser}
57 %error-verbose
58 %debug
59
60 /* We use SCMs to do strings, because it saves us the trouble of
61 deleting them.  Let's hope that a stack overflow doesn't trigger a move
62 of the parse stack onto the heap. */
63
64 %left PREC_BOT
65 %nonassoc REPEAT
66 %nonassoc ALTERNATIVE
67
68 /* The above precedences tackle the shift/reduce problem
69
70 1.  \repeat
71         \repeat .. \alternative
72
73     \repeat { \repeat .. \alternative }
74
75 or
76
77     \repeat { \repeat } \alternative
78 */
79
80 %nonassoc COMPOSITE
81 %left ADDLYRICS
82
83  /* ADDLYRICS needs to have lower precedence than argument scanning,
84   * or we won't be able to tell music apart from closed_music without
85   * lookahead in the context of function calls.
86   */
87
88 %nonassoc DEFAULT
89
90  /* \default is only applied after exhausting function arguments */
91
92 %nonassoc FUNCTION_ARGLIST
93
94  /* expressions with units are permitted into argument lists */
95
96 %right PITCH_IDENTIFIER NOTENAME_PITCH TONICNAME_PITCH
97       UNSIGNED REAL DURATION_IDENTIFIER ':'
98
99  /* The above are the symbols that can start optional function arguments
100     that are recognized in the grammar rather than by predicate
101  */
102
103 %nonassoc NUMBER_IDENTIFIER '/'
104
105  /* Number-unit expressions, where permitted, are concatenated into
106   * function arguments, just like fractions and tremoli.  Tremoli must
107   * not have higher precedence than UNSIGNED, or Lilypond will not
108   * join ':' with a following optional number.
109   */
110
111 %left PREC_TOP
112
113
114
115
116 %pure_parser
117 %locations
118
119
120
121 %{ // -*-Fundamental-*-
122
123 /*
124 FIXME:
125
126    * The rules for who is protecting what are very shady.  Uniformise
127      this.
128
129    * There are too many lexical modes?
130 */
131
132 #include "config.hh"
133
134 #include <cctype>
135 #include <cstdlib>
136 #include <cstdio>
137 using namespace std;
138
139 #include "book.hh"
140 #include "context-def.hh"
141 #include "context-mod.hh"
142 #include "dimensions.hh"
143 #include "file-path.hh"
144 #include "input.hh"
145 #include "international.hh"
146 #include "lily-guile.hh"
147 #include "lily-lexer.hh"
148 #include "lily-parser.hh"
149 #include "main.hh"
150 #include "misc.hh"
151 #include "music.hh"
152 #include "output-def.hh"
153 #include "paper-book.hh"
154 #include "scm-hash.hh"
155 #include "score.hh"
156 #include "text-interface.hh"
157 #include "warn.hh"
158
159 void
160 Lily_parser::parser_error (Input const *i, Lily_parser *parser, SCM *, string s)
161 {
162         parser->parser_error (*i, s);
163 }
164
165 #define MYBACKUP(Token, Value, Location)                                \
166 do                                                                      \
167         if (yychar == YYEMPTY)                                          \
168         {                                                               \
169                 if (Token)                                              \
170                         parser->lexer_->push_extra_token (Token, Value); \
171                 parser->lexer_->push_extra_token (BACKUP);              \
172         } else {                                                        \
173                 parser->parser_error                                    \
174                         (Location, _("Too much lookahead"));            \
175         }                                                               \
176 while (0)
177
178
179 #define MYREPARSE(Location, Pred, Token, Value)                         \
180 do                                                                      \
181         if (yychar == YYEMPTY)                                          \
182         {                                                               \
183                 parser->lexer_->push_extra_token (Token, Value);        \
184                 parser->lexer_->push_extra_token (REPARSE,              \
185                                                   Pred);                \
186         } else {                                                        \
187                 parser->parser_error                                    \
188                         (Location, _("Too much lookahead"));            \
189         }                                                               \
190 while (0)
191
192 %}
193
194
195 %{
196
197 #define MY_MAKE_MUSIC(x, spot)  make_music_with_input (ly_symbol2scm (x), spot)
198
199 /* ES TODO:
200 - Don't use lily module, create a new module instead.
201 - delay application of the function
202 */
203 #define LOWLEVEL_MAKE_SYNTAX(proc, args)        \
204   scm_apply_0 (proc, args)
205 /* Syntactic Sugar. */
206 #define MAKE_SYNTAX(name, location, ...)        \
207   LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant (name), scm_list_n (parser->self_scm (), make_input (location) , ##__VA_ARGS__, SCM_UNDEFINED))
208 #define START_MAKE_SYNTAX(name, ...)                                    \
209         scm_list_n (ly_lily_module_constant (name) , ##__VA_ARGS__, SCM_UNDEFINED)
210 #define FINISH_MAKE_SYNTAX(start, location, ...)                        \
211         LOWLEVEL_MAKE_SYNTAX (scm_car (start), scm_cons2 (parser->self_scm (), make_input (location), scm_append_x (scm_list_2 (scm_cdr (start), scm_list_n (__VA_ARGS__, SCM_UNDEFINED)))))
212
213 SCM get_next_unique_context_id ();
214 SCM get_next_unique_lyrics_context_id ();
215
216 #undef _
217 #if !HAVE_GETTEXT
218 #define _(x) x
219 #else
220 #include <libintl.h>
221 #define _(x) gettext (x)
222 #endif
223
224
225 static Music *make_music_with_input (SCM name, Input where);
226 SCM check_scheme_arg (Lily_parser *parser, Input loc,
227                       SCM arg, SCM args, SCM pred);
228 SCM make_music_from_simple (Lily_parser *parser, Input loc, SCM pitch);
229 SCM loc_on_music (Input loc, SCM arg);
230 SCM make_chord_elements (Input loc, SCM pitch, SCM dur, SCM modification_list);
231 SCM make_chord_step (SCM step, Rational alter);
232 SCM make_simple_markup (SCM a);
233 bool is_duration (int t);
234 bool is_regular_identifier (SCM id);
235 int yylex (YYSTYPE *s, YYLTYPE *loc, Lily_parser *parser);
236
237 %}
238
239 /* The third option is an alias that will be used to display the
240    syntax error.  Bison CVS now correctly handles backslash escapes.
241
242    FIXME: Bison needs to translate some of these, eg, STRING.
243
244 */
245
246 /* Keyword tokens with plain escaped name.  */
247 %token END_OF_FILE 0 "end of input"
248 %token ACCEPTS "\\accepts"
249 %token ADDLYRICS "\\addlyrics"
250 %token ALIAS "\\alias"
251 %token ALTERNATIVE "\\alternative"
252 %token BOOK "\\book"
253 %token BOOKPART "\\bookpart"
254 %token CHANGE "\\change"
255 %token CHORDMODE "\\chordmode"
256 %token CHORDS "\\chords"
257 %token CONSISTS "\\consists"
258 %token CONTEXT "\\context"
259 %token DEFAULT "\\default"
260 %token DEFAULTCHILD "\\defaultchild"
261 %token DENIES "\\denies"
262 %token DESCRIPTION "\\description"
263 %token DRUMMODE "\\drummode"
264 %token DRUMS "\\drums"
265 %token FIGUREMODE "\\figuremode"
266 %token FIGURES "\\figures"
267 %token HEADER "\\header"
268 %token INVALID "\\version-error"
269 %token LAYOUT "\\layout"
270 %token LYRICMODE "\\lyricmode"
271 %token LYRICS "\\lyrics"
272 %token LYRICSTO "\\lyricsto"
273 %token MARKUP "\\markup"
274 %token MARKUPLIST "\\markuplist"
275 %token MIDI "\\midi"
276 %token NAME "\\name"
277 %token NOTEMODE "\\notemode"
278 %token OVERRIDE "\\override"
279 %token PAPER "\\paper"
280 %token REMOVE "\\remove"
281 %token REPEAT "\\repeat"
282 %token REST "\\rest"
283 %token REVERT "\\revert"
284 %token SCORE "\\score"
285 %token SEQUENTIAL "\\sequential"
286 %token SET "\\set"
287 %token SIMULTANEOUS "\\simultaneous"
288 %token TEMPO "\\tempo"
289 %token TYPE "\\type"
290 %token UNSET "\\unset"
291 %token WITH "\\with"
292
293 /* Keyword token exceptions.  */
294 %token NEWCONTEXT "\\new"
295
296
297 /* Other string tokens.  */
298
299 %token CHORD_BASS "/+"
300 %token CHORD_CARET "^"
301 %token CHORD_COLON ":"
302 %token CHORD_MINUS "-"
303 %token CHORD_SLASH "/"
304 %token ANGLE_OPEN "<"
305 %token ANGLE_CLOSE ">"
306 %token DOUBLE_ANGLE_OPEN "<<"
307 %token DOUBLE_ANGLE_CLOSE ">>"
308 %token E_BACKSLASH "\\"
309 %token E_ANGLE_CLOSE "\\>"
310 %token E_CHAR "\\C[haracter]"
311 %token E_CLOSE "\\)"
312 %token E_EXCLAMATION "\\!"
313 %token E_BRACKET_OPEN "\\["
314 %token E_OPEN "\\("
315 %token E_BRACKET_CLOSE "\\]"
316 %token E_ANGLE_OPEN "\\<"
317 %token E_PLUS "\\+"
318 %token E_TILDE "\\~"
319 %token EXTENDER "__"
320
321 /*
322 If we give names, Bison complains.
323 */
324 %token FIGURE_CLOSE /* "\\>" */
325 %token FIGURE_OPEN /* "\\<" */
326 %token FIGURE_SPACE "_"
327 %token HYPHEN "--"
328
329 %token CHORDMODIFIERS
330 %token LYRIC_MARKUP
331 %token MULTI_MEASURE_REST
332
333
334 %token E_UNSIGNED
335 %token UNSIGNED
336
337 /* Artificial tokens, for more generic function syntax */
338 %token EXPECT_MARKUP "markup?"
339 %token EXPECT_PITCH "ly:pitch?"
340 %token EXPECT_DURATION "ly:duration?"
341 %token EXPECT_SCM "scheme?"
342 %token BACKUP "(backed-up?)"
343 %token REPARSE "(reparsed?)"
344 %token EXPECT_MARKUP_LIST "markup-list?"
345 %token EXPECT_OPTIONAL "optional?"
346 /* After the last argument. */
347 %token EXPECT_NO_MORE_ARGS;
348
349 /* An artificial token for parsing embedded Lilypond */
350 %token EMBEDDED_LILY "#{"
351
352 %token BOOK_IDENTIFIER
353 %token CHORDMODIFIER_PITCH
354 %token CHORD_MODIFIER
355 %token CHORD_REPETITION
356 %token CONTEXT_DEF_IDENTIFIER
357 %token CONTEXT_MOD_IDENTIFIER
358 %token DRUM_PITCH
359 %token PITCH_IDENTIFIER
360 %token DURATION_IDENTIFIER
361 %token EVENT_IDENTIFIER
362 %token EVENT_FUNCTION
363 %token FRACTION
364 %token LYRICS_STRING
365 %token LYRIC_ELEMENT
366 %token MARKUP_FUNCTION
367 %token MARKUP_LIST_FUNCTION
368 %token MARKUP_IDENTIFIER
369 %token MARKUPLIST_IDENTIFIER
370 %token MUSIC_FUNCTION
371 %token MUSIC_IDENTIFIER
372 %token NOTENAME_PITCH
373 %token NUMBER_IDENTIFIER
374 %token OUTPUT_DEF_IDENTIFIER
375 %token REAL
376 %token RESTNAME
377 %token SCM_FUNCTION
378 %token SCM_IDENTIFIER
379 %token SCM_TOKEN
380 %token SCORE_IDENTIFIER
381 %token STRING
382 %token TONICNAME_PITCH
383
384 %left '-' '+'
385
386 /* We don't assign precedence to / and *, because we might need varied
387 prec levels in different prods */
388
389 %left UNARY_MINUS
390
391 %%
392
393 start_symbol:
394         lilypond
395         | EMBEDDED_LILY {
396                 SCM nn = parser->lexer_->lookup_identifier ("pitchnames");
397                 parser->lexer_->push_note_state (nn);
398         } embedded_lilypond {
399                 parser->lexer_->pop_state ();
400                 *retval = $3;
401         }
402         ;
403
404 lilypond:       /* empty */ { $$ = SCM_UNSPECIFIED; }
405         | lilypond toplevel_expression {
406         }
407         | lilypond assignment {
408         }
409         | lilypond error {
410                 parser->error_level_ = 1;
411         }
412         | lilypond INVALID      {
413                 parser->error_level_ = 1;
414         }
415         ;
416
417
418 toplevel_expression:
419         {
420                 parser->lexer_->add_scope (get_header (parser));
421         } lilypond_header {
422                 parser->lexer_->set_identifier (ly_symbol2scm ("$defaultheader"), $2);
423         }
424         | book_block {
425                 SCM proc = parser->lexer_->lookup_identifier ("toplevel-book-handler");
426                 scm_call_2 (proc, parser->self_scm (), $1);
427         }
428         | bookpart_block {
429                 SCM proc = parser->lexer_->lookup_identifier ("toplevel-bookpart-handler");
430                 scm_call_2 (proc, parser->self_scm (), $1);
431         }
432         | score_block {
433                 SCM proc = parser->lexer_->lookup_identifier ("toplevel-score-handler");
434                 scm_call_2 (proc, parser->self_scm (), $1);
435         }
436         | composite_music {
437                 SCM proc = parser->lexer_->lookup_identifier ("toplevel-music-handler");
438                 scm_call_2 (proc, parser->self_scm (), $1);
439         }
440         | full_markup {
441                 SCM proc = parser->lexer_->lookup_identifier ("toplevel-text-handler");
442                 scm_call_2 (proc, parser->self_scm (), scm_list_1 ($1));
443         }
444         | full_markup_list {
445                 SCM proc = parser->lexer_->lookup_identifier ("toplevel-text-handler");
446                 scm_call_2 (proc, parser->self_scm (), $1);
447         }
448         | SCM_TOKEN {
449                 // Evaluate and ignore #xxx, as opposed to \xxx
450                 parser->lexer_->eval_scm_token ($1);
451         }
452         | embedded_scm_active
453         {
454                 SCM out = SCM_UNDEFINED;
455                 if (Text_interface::is_markup ($1))
456                         out = scm_list_1 ($1);
457                 else if (Text_interface::is_markup_list ($1))
458                         out = $1;
459                 if (scm_is_pair (out))
460                 {
461                         SCM proc = parser->lexer_->lookup_identifier ("toplevel-text-handler");
462                         scm_call_2 (proc, parser->self_scm (), out);
463                 } else if (!scm_is_eq ($1, SCM_UNSPECIFIED))
464                         parser->parser_error (@1, _("bad expression type"));
465         }
466         | output_def {
467                 SCM id = SCM_EOL;
468                 Output_def * od = unsmob_output_def ($1);
469
470                 if (od->c_variable ("is-paper") == SCM_BOOL_T)
471                         id = ly_symbol2scm ("$defaultpaper");
472                 else if (od->c_variable ("is-midi") == SCM_BOOL_T)
473                         id = ly_symbol2scm ("$defaultmidi");
474                 else if (od->c_variable ("is-layout") == SCM_BOOL_T)
475                         id = ly_symbol2scm ("$defaultlayout");
476
477                 parser->lexer_->set_identifier (id, $1);
478         }
479         ;
480
481 embedded_scm_bare:
482         SCM_TOKEN
483         {
484                 $$ = parser->lexer_->eval_scm_token ($1);
485         }
486         | SCM_IDENTIFIER
487         ;
488
489 embedded_scm_active:
490         SCM_IDENTIFIER
491         | scm_function_call
492         ;
493
494 embedded_scm_bare_arg:
495         embedded_scm_bare
496         | STRING
497         | full_markup
498         | full_markup_list
499         | context_modification
500         | score_block
501         | context_def_spec_block
502         | book_block
503         | bookpart_block
504         | output_def
505         ;
506
507 /* The generic version may end in music, or not */
508
509 embedded_scm:
510         embedded_scm_bare
511         | scm_function_call
512         ;
513
514 embedded_scm_arg:
515         embedded_scm_bare_arg
516         | scm_function_call
517         | music_arg
518         ;
519
520 scm_function_call:
521         SCM_FUNCTION function_arglist {
522                 $$ = MAKE_SYNTAX ("music-function", @$,
523                                          $1, $2);
524         }
525         ;
526
527 embedded_lilypond:
528         /* empty */
529         {
530                 $$ = MAKE_SYNTAX ("void-music", @$);
531         }
532         | identifier_init
533         | music_embedded music_embedded music_list {
534                 $3 = scm_reverse_x ($3, SCM_EOL);
535                 if (unsmob_music ($2))
536                         $3 = scm_cons ($2, $3);
537                 if (unsmob_music ($1))
538                         $3 = scm_cons ($1, $3);
539                 $$ = MAKE_SYNTAX ("sequential-music", @$, $3);
540         }
541         | error {
542                 parser->error_level_ = 1;
543                 $$ = SCM_UNSPECIFIED;
544         }
545         | INVALID embedded_lilypond {
546                 parser->error_level_ = 1;
547                 $$ = $2;
548         }
549         ;
550
551
552 lilypond_header_body:
553         /* empty */ { $$ = SCM_UNSPECIFIED; }
554         | lilypond_header_body assignment  {
555
556         }
557         | lilypond_header_body embedded_scm  {
558
559         }
560         ;
561
562 lilypond_header:
563         HEADER '{' lilypond_header_body '}'     {
564                 $$ = parser->lexer_->remove_scope ();
565         }
566         ;
567
568 /*
569         DECLARATIONS
570 */
571 assignment_id:
572         STRING          { $$ = $1; }
573         | LYRICS_STRING { $$ = $1; }
574         ;
575
576 assignment:
577         assignment_id '=' identifier_init  {
578                 parser->lexer_->set_identifier ($1, $3);
579                 $$ = SCM_UNSPECIFIED;
580         }
581         | assignment_id property_path '=' identifier_init {
582                 SCM path = scm_cons (scm_string_to_symbol ($1), $2);
583                 parser->lexer_->set_identifier (path, $4);
584                 $$ = SCM_UNSPECIFIED;
585         }
586         ;
587
588
589 identifier_init:
590         score_block
591         | book_block
592         | bookpart_block
593         | output_def
594         | context_def_spec_block
595         | music_assign
596         | post_event_nofinger
597         | number_expression
598         | FRACTION
599         | string
600         | embedded_scm
601         | full_markup_list
602         | context_modification
603         ;
604
605 context_def_spec_block:
606         CONTEXT '{' context_def_spec_body '}'
607                 {
608                 $$ = $3;
609         }
610         ;
611
612 context_mod_arg:
613         embedded_scm
614         | composite_music
615         ;
616
617 context_mod_embedded:
618         context_mod_arg
619         {
620                 if (unsmob_music ($1)) {
621                         SCM proc = parser->lexer_->lookup_identifier ("context-mod-music-handler");
622                         $1 = scm_call_2 (proc, parser->self_scm (), $1);
623                 }
624                 if (unsmob_context_mod ($1))
625                         $$ = $1;
626                 else {
627                         parser->parser_error (@1, _ ("not a context mod"));
628                 }
629         }
630         ;
631
632
633 context_def_spec_body:
634         /**/ {
635                 $$ = Context_def::make_scm ();
636                 unsmob_context_def ($$)->origin ()->set_spot (@$);
637         }
638         | CONTEXT_DEF_IDENTIFIER {
639                 $$ = $1;
640                 unsmob_context_def ($$)->origin ()->set_spot (@$);
641         }
642         | context_def_spec_body context_mod {
643                 unsmob_context_def ($$)->add_context_mod ($2);
644         }
645         | context_def_spec_body context_modification {
646                 Context_def *td = unsmob_context_def ($$);
647                 SCM new_mods = unsmob_context_mod ($2)->get_mods ();
648                 for (SCM m = new_mods; scm_is_pair (m); m = scm_cdr (m)) {
649                     td->add_context_mod (scm_car (m));
650                 }
651         }
652         | context_def_spec_body context_mod_embedded {
653                 Context_def *td = unsmob_context_def ($$);
654                 SCM new_mods = unsmob_context_mod ($2)->get_mods ();
655                 for (SCM m = new_mods; scm_is_pair (m); m = scm_cdr (m)) {
656                     td->add_context_mod (scm_car (m));
657                 }
658         }
659         ;
660
661
662
663 book_block:
664         BOOK '{' book_body '}'  {
665                 $$ = $3;
666                 pop_paper (parser);
667                 parser->lexer_->set_identifier (ly_symbol2scm ("$current-book"), SCM_BOOL_F);
668         }
669         ;
670
671 /* FIXME:
672    * Use 'handlers' like for toplevel-* stuff?
673    * grok \layout and \midi?  */
674 book_body:
675         {
676                 Book *book = new Book;
677                 init_papers (parser);
678                 book->origin ()->set_spot (@$);
679                 book->paper_ = dynamic_cast<Output_def*> (unsmob_output_def (parser->lexer_->lookup_identifier ("$defaultpaper"))->clone ());
680                 book->paper_->unprotect ();
681                 push_paper (parser, book->paper_);
682                 book->header_ = get_header (parser);
683                 $$ = book->unprotect ();
684                 parser->lexer_->set_identifier (ly_symbol2scm ("$current-book"), $$);
685         }
686         | BOOK_IDENTIFIER {
687                 unsmob_book ($1)->origin ()->set_spot (@$);
688                 parser->lexer_->set_identifier (ly_symbol2scm ("$current-book"), $1);
689         }
690         | book_body paper_block {
691                 unsmob_book ($1)->paper_ = unsmob_output_def ($2);
692                 set_paper (parser, unsmob_output_def ($2));
693         }
694         | book_body bookpart_block {
695                 SCM proc = parser->lexer_->lookup_identifier ("book-bookpart-handler");
696                 scm_call_2 (proc, $1, $2);
697         }
698         | book_body score_block {
699                 SCM proc = parser->lexer_->lookup_identifier ("book-score-handler");
700                 scm_call_2 (proc, $1, $2);
701         }
702         | book_body composite_music {
703                 SCM proc = parser->lexer_->lookup_identifier ("book-music-handler");
704                 scm_call_3 (proc, parser->self_scm (), $1, $2);
705         }
706         | book_body full_markup {
707                 SCM proc = parser->lexer_->lookup_identifier ("book-text-handler");
708                 scm_call_2 (proc, $1, scm_list_1 ($2));
709         }
710         | book_body full_markup_list {
711                 SCM proc = parser->lexer_->lookup_identifier ("book-text-handler");
712                 scm_call_2 (proc, $1, $2);
713         }
714         | book_body SCM_TOKEN {
715                 // Evaluate and ignore #xxx, as opposed to \xxx
716                 parser->lexer_->eval_scm_token ($2);
717         }
718         | book_body embedded_scm_active
719         {
720                 SCM out = SCM_UNDEFINED;
721                 if (Text_interface::is_markup ($2))
722                         out = scm_list_1 ($2);
723                 else if (Text_interface::is_markup_list ($2))
724                         out = $2;
725                 if (scm_is_pair (out))
726                 {
727                         SCM proc = parser->lexer_->lookup_identifier ("book-text-handler");
728                         scm_call_2 (proc, $1, out);
729                 } else if (!scm_is_eq ($2, SCM_UNSPECIFIED))
730                         parser->parser_error (@2, _("bad expression type"));
731         }
732         | book_body
733         {
734                 parser->lexer_->add_scope (unsmob_book ($1)->header_);
735         } lilypond_header
736         | book_body error {
737                 Book *book = unsmob_book ($1);
738                 book->paper_ = 0;
739                 book->scores_ = SCM_EOL;
740                 book->bookparts_ = SCM_EOL;
741         }
742         ;
743
744 bookpart_block:
745         BOOKPART '{' bookpart_body '}' {
746                 $$ = $3;
747                 parser->lexer_->set_identifier (ly_symbol2scm ("$current-bookpart"), SCM_BOOL_F);
748         }
749         ;
750
751 bookpart_body:
752         {
753                 Book *book = new Book;
754                 book->origin ()->set_spot (@$);
755                 $$ = book->unprotect ();
756                 parser->lexer_->set_identifier (ly_symbol2scm ("$current-bookpart"), $$);
757         }
758         | BOOK_IDENTIFIER {
759                 unsmob_book ($1)->origin ()->set_spot (@$);
760                 parser->lexer_->set_identifier (ly_symbol2scm ("$current-bookpart"), $1);
761         }
762         | bookpart_body paper_block {
763                 unsmob_book ($$)->paper_ = unsmob_output_def ($2);
764         }
765         | bookpart_body score_block {
766                 SCM proc = parser->lexer_->lookup_identifier ("bookpart-score-handler");
767                 scm_call_2 (proc, $1, $2);
768         }
769         | bookpart_body composite_music {
770                 SCM proc = parser->lexer_->lookup_identifier ("bookpart-music-handler");
771                 scm_call_3 (proc, parser->self_scm (), $1, $2);
772         }
773         | bookpart_body full_markup {
774                 SCM proc = parser->lexer_->lookup_identifier ("bookpart-text-handler");
775                 scm_call_2 (proc, $1, scm_list_1 ($2));
776         }
777         | bookpart_body full_markup_list {
778                 SCM proc = parser->lexer_->lookup_identifier ("bookpart-text-handler");
779                 scm_call_2 (proc, $1, $2);
780         }
781         | bookpart_body SCM_TOKEN {
782                 // Evaluate and ignore #xxx, as opposed to \xxx
783                 parser->lexer_->eval_scm_token ($2);
784         }
785         | bookpart_body embedded_scm_active
786         {
787                 SCM out = SCM_UNDEFINED;
788                 if (Text_interface::is_markup ($2))
789                         out = scm_list_1 ($2);
790                 else if (Text_interface::is_markup_list ($2))
791                         out = $2;
792                 if (scm_is_pair (out))
793                 {
794                         SCM proc = parser->lexer_->lookup_identifier ("bookpart-text-handler");
795                         scm_call_2 (proc, $1, out);
796                 } else if (!scm_is_eq ($2, SCM_UNSPECIFIED))
797                         parser->parser_error (@2, _("bad expression type"));
798         }
799         | bookpart_body
800         {
801                 Book *book = unsmob_book ($1);
802                 if (!ly_is_module (book->header_))
803                         book->header_ = ly_make_module (false);
804                 parser->lexer_->add_scope (book->header_);
805         } lilypond_header
806         | bookpart_body error {
807                 Book *book = unsmob_book ($1);
808                 book->paper_ = 0;
809                 book->scores_ = SCM_EOL;
810         }
811         ;
812
813 score_block:
814         SCORE '{' score_body '}'        {
815                 $$ = $3;
816         }
817         ;
818
819 score_body:
820         music {
821                 SCM scorify = ly_lily_module_constant ("scorify-music");
822                 $$ = scm_call_2 (scorify, $1, parser->self_scm ());
823
824                 unsmob_score ($$)->origin ()->set_spot (@$);
825         }
826         | SCORE_IDENTIFIER {
827                 unsmob_score ($$)->origin ()->set_spot (@$);
828         }
829         | score_body
830         {
831                 Score *score = unsmob_score ($1);
832                 if (!ly_is_module (score->get_header ()))
833                         score->set_header (ly_make_module (false));
834                 parser->lexer_->add_scope (score->get_header ());
835         } lilypond_header
836         | score_body output_def {
837                 Output_def *od = unsmob_output_def ($2);
838                 if (od->lookup_variable (ly_symbol2scm ("is-paper")) == SCM_BOOL_T)
839                 {
840                         parser->parser_error (@2, _("\\paper cannot be used in \\score, use \\layout instead"));
841
842                 }
843                 else
844                 {
845                         unsmob_score ($1)->add_output_def (od);
846                 }
847         }
848         | score_body error {
849                 unsmob_score ($$)->error_found_ = true;
850         }
851         ;
852
853
854 /*
855         OUTPUT DEF
856 */
857
858 paper_block:
859         output_def {
860                 Output_def *od = unsmob_output_def ($1);
861
862                 if (od->lookup_variable (ly_symbol2scm ("is-paper")) != SCM_BOOL_T)
863                 {
864                         parser->parser_error (@1, _ ("need \\paper for paper block"));
865                         $$ = get_paper (parser)->unprotect ();
866                 }
867         }
868         ;
869
870
871 output_def:
872         output_def_body '}' {
873                 $$ = $1;
874
875                 parser->lexer_->remove_scope ();
876                 parser->lexer_->pop_state ();
877         }
878         ;
879
880 output_def_head:
881         PAPER {
882                 Output_def *p = get_paper (parser);
883                 p->input_origin_ = @$;
884                 parser->lexer_->add_scope (p->scope_);
885                 $$ = p->unprotect ();
886         }
887         | MIDI    {
888                 Output_def *p = get_midi (parser);
889                 $$ = p->unprotect ();
890                 parser->lexer_->add_scope (p->scope_);
891         }
892         | LAYOUT        {
893                 Output_def *p = get_layout (parser);
894
895                 parser->lexer_->add_scope (p->scope_);
896                 $$ = p->unprotect ();
897         }
898         ;
899
900 output_def_head_with_mode_switch:
901         output_def_head {
902                 parser->lexer_->push_initial_state ();
903                 $$ = $1;
904         }
905         ;
906
907 // We need this weird nonterminal because both music as well as a
908 // context definition can start with \context and the difference is
909 // only apparent after looking at the next token.  If it is '{', there
910 // is still time to escape from notes mode.
911
912 music_or_context_def:
913         music_arg
914         {
915                 parser->lexer_->pop_state ();
916         }
917         | CONTEXT
918         {
919                 parser->lexer_->pop_state ();
920         } '{' context_def_spec_body '}'
921         {
922                 $$ = $4;
923         }
924         ;
925
926 output_def_body:
927         output_def_head_with_mode_switch '{' {
928                 $$ = $1;
929                 unsmob_output_def ($$)->input_origin_.set_spot (@$);
930         }
931         | output_def_head_with_mode_switch '{' OUTPUT_DEF_IDENTIFIER    {
932                 Output_def *o = unsmob_output_def ($3);
933                 o->input_origin_.set_spot (@$);
934                 $$ = o->self_scm ();
935                 parser->lexer_->remove_scope ();
936                 parser->lexer_->add_scope (o->scope_);
937         }
938         | output_def_body assignment  {
939
940         }
941         | output_def_body embedded_scm  {
942
943         }
944         | output_def_body
945         {
946                 SCM nn = parser->lexer_->lookup_identifier ("pitchnames");
947                 parser->lexer_->push_note_state (nn);
948         } music_or_context_def
949         {
950                 if (unsmob_context_def ($3))
951                         assign_context_def (unsmob_output_def ($1), $3);
952                 else {
953
954                         SCM proc = parser->lexer_->lookup_identifier
955                                      ("output-def-music-handler");
956                         scm_call_3 (proc, parser->self_scm (),
957                                     $1, $3);
958                 }
959         }
960         | output_def_body error {
961
962         }
963         ;
964
965 tempo_event:
966         TEMPO steno_duration '=' tempo_range    {
967                 $$ = MAKE_SYNTAX ("tempo", @$, SCM_EOL, $2, $4);
968         }
969         | TEMPO scalar_closed steno_duration '=' tempo_range    {
970                 $$ = MAKE_SYNTAX ("tempo", @$, $2, $3, $5);
971         }
972         | TEMPO scalar {
973                 $$ = MAKE_SYNTAX ("tempo", @$, $2);
974         }
975         ;
976
977 /*
978 The representation of a  list is reversed to have efficient append.  */
979
980 music_list:
981         /* empty */ {
982                 $$ = SCM_EOL;
983         }
984         | music_list music_embedded {
985                 if (unsmob_music ($2))
986                         $$ = scm_cons ($2, $1);
987         }
988         | music_list error {
989                 Music *m = MY_MAKE_MUSIC("Music", @$);
990                 // ugh. code dup
991                 m->set_property ("error-found", SCM_BOOL_T);
992                 $$ = scm_cons (m->self_scm (), $1);
993                 m->unprotect (); /* UGH */
994         }
995         ;
996
997 braced_music_list:
998         '{' music_list '}'
999         {
1000                 $$ = scm_reverse_x ($2, SCM_EOL);
1001         }
1002         ;
1003
1004 music:  music_arg
1005         | lyric_element_music
1006         ;
1007
1008 music_embedded:
1009         music
1010         | embedded_scm
1011         {
1012                 if (unsmob_music ($1)
1013                     || scm_is_eq ($1, SCM_UNSPECIFIED))
1014                         $$ = $1;
1015                 else
1016                 {
1017                         @$.warning (_ ("Ignoring non-music expression"));
1018                         $$ = SCM_UNSPECIFIED;
1019                 }
1020         }
1021         ;
1022
1023 music_arg:
1024         simple_music
1025         {
1026                 $$ = make_music_from_simple (parser, @1, $1);
1027                 if (!unsmob_music ($$))
1028                         parser->parser_error (@1, _ ("music expected"));
1029         }
1030         | composite_music %prec COMPOSITE
1031         ;
1032
1033 music_assign:
1034         simple_music
1035         | composite_music %prec COMPOSITE
1036         | lyric_element_music
1037         ;
1038
1039 repeated_music:
1040         REPEAT simple_string unsigned_number music
1041         {
1042                 $$ = MAKE_SYNTAX ("repeat", @$, $2, $3, $4, SCM_EOL);
1043         }
1044         | REPEAT simple_string unsigned_number music ALTERNATIVE braced_music_list
1045         {
1046                 $$ = MAKE_SYNTAX ("repeat", @$, $2, $3, $4, $6);
1047         }
1048         ;
1049
1050 sequential_music:
1051         SEQUENTIAL braced_music_list {
1052                 $$ = MAKE_SYNTAX ("sequential-music", @$, $2);
1053         }
1054         | braced_music_list {
1055                 $$ = MAKE_SYNTAX ("sequential-music", @$, $1);
1056         }
1057         ;
1058
1059 simultaneous_music:
1060         SIMULTANEOUS braced_music_list {
1061                 $$ = MAKE_SYNTAX ("simultaneous-music", @$, $2);
1062         }
1063         | DOUBLE_ANGLE_OPEN music_list DOUBLE_ANGLE_CLOSE       {
1064                 $$ = MAKE_SYNTAX ("simultaneous-music", @$, scm_reverse_x ($2, SCM_EOL));
1065         }
1066         ;
1067
1068 simple_music:
1069         event_chord
1070         | music_property_def
1071         | context_change
1072         ;
1073
1074 context_modification:
1075         WITH { parser->lexer_->push_initial_state (); } '{' context_mod_list '}'
1076         {
1077                 parser->lexer_->pop_state ();
1078                 $$ = $4;
1079         }
1080         | WITH CONTEXT_MOD_IDENTIFIER
1081         {
1082                 $$ = $2;
1083         }
1084         | CONTEXT_MOD_IDENTIFIER
1085         {
1086                 $$ = $1;
1087         }
1088         | WITH embedded_scm_closed
1089         {
1090                 if (unsmob_context_mod ($2))
1091                         $$ = $2;
1092                 else {
1093                         parser->parser_error (@2, _ ("not a context mod"));
1094                         $$ = Context_mod ().smobbed_copy ();
1095                 }
1096         }
1097         ;
1098
1099 optional_context_mod:
1100         /**/ {
1101             $$ = SCM_EOL;
1102         }
1103         | context_modification
1104         {
1105               $$ = $1;
1106         }
1107         ;
1108
1109 context_mod_list:
1110         /**/ {
1111             $$ = Context_mod ().smobbed_copy ();
1112         }
1113         | context_mod_list context_mod  {
1114                  unsmob_context_mod ($1)->add_context_mod ($2);
1115         }
1116         | context_mod_list CONTEXT_MOD_IDENTIFIER {
1117                  Context_mod *md = unsmob_context_mod ($2);
1118                  if (md)
1119                      unsmob_context_mod ($1)->add_context_mods (md->get_mods ());
1120         }
1121         | context_mod_list context_mod_embedded {
1122                 unsmob_context_mod ($1)->add_context_mods
1123                         (unsmob_context_mod ($2)->get_mods ());
1124         }
1125         ;
1126
1127 composite_music:
1128         complex_music
1129         | music_bare
1130         ;
1131
1132 /* Music that can be parsed without lookahead */
1133 closed_music:
1134         music_bare
1135         | complex_music_prefix closed_music
1136         {
1137                 $$ = FINISH_MAKE_SYNTAX ($1, @$, $2);
1138         }
1139         | music_function_call_closed
1140         ;
1141
1142 music_bare:
1143         mode_changed_music
1144         | MUSIC_IDENTIFIER
1145         | grouped_music_list
1146         ;
1147
1148 grouped_music_list:
1149         simultaneous_music              { $$ = $1; }
1150         | sequential_music              { $$ = $1; }
1151         ;
1152
1153 /* An argument list. If a function \foo expects scm scm pitch, then the lexer expands \foo into the token sequence:
1154  MUSIC_FUNCTION EXPECT_PITCH EXPECT_SCM EXPECT_SCM EXPECT_NO_MORE_ARGS
1155 and this rule returns the reversed list of arguments. */
1156
1157 function_arglist_skip:
1158         function_arglist_common
1159         | EXPECT_OPTIONAL EXPECT_PITCH function_arglist_skip
1160         {
1161                 $$ = scm_cons ($1, $3);
1162         } %prec FUNCTION_ARGLIST
1163         | EXPECT_OPTIONAL EXPECT_DURATION function_arglist_skip
1164         {
1165                 $$ = scm_cons ($1, $3);
1166         } %prec FUNCTION_ARGLIST
1167         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_skip
1168         {
1169                 $$ = scm_cons ($1, $3);
1170         } %prec FUNCTION_ARGLIST
1171         ;
1172
1173
1174 function_arglist_nonbackup_common:
1175         EXPECT_OPTIONAL EXPECT_PITCH function_arglist pitch_also_in_chords {
1176                 $$ = scm_cons ($4, $3);
1177         }
1178         | EXPECT_OPTIONAL EXPECT_DURATION function_arglist_closed duration_length {
1179                 $$ = scm_cons ($4, $3);
1180         }
1181         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed FRACTION
1182         {
1183                 $$ = check_scheme_arg (parser, @4, $4, $3, $2);
1184         }
1185         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed post_event_nofinger
1186         {
1187                 $$ = check_scheme_arg (parser, @4, $4, $3, $2);
1188         }
1189         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed '-' UNSIGNED
1190         {
1191                 SCM n = scm_difference ($5, SCM_UNDEFINED);
1192                 if (scm_is_true (scm_call_1 ($2, n)))
1193                         $$ = scm_cons (n, $3);
1194                 else {
1195                         Music *t = MY_MAKE_MUSIC ("FingeringEvent", @5);
1196                         t->set_property ("digit", $5);
1197                         $$ = t->unprotect ();
1198                         if (scm_is_true (scm_call_1 ($2, $$)))
1199                                 $$ = scm_cons ($$, $3);
1200                         else
1201                                 $$ = check_scheme_arg (parser, @4, n, $3, $2);
1202                 }
1203                 
1204         }
1205         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed '-' REAL
1206         {
1207                 $$ = check_scheme_arg (parser, @4,
1208                                        scm_difference ($5, SCM_UNDEFINED),
1209                                        $3, $2);
1210         }
1211         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed '-' NUMBER_IDENTIFIER
1212         {
1213                 $$ = check_scheme_arg (parser, @4,
1214                                        scm_difference ($5, SCM_UNDEFINED),
1215                                        $3, $2);
1216         }
1217         ;
1218
1219 function_arglist_closed_nonbackup:
1220         function_arglist_nonbackup_common
1221         | EXPECT_OPTIONAL EXPECT_SCM function_arglist embedded_scm_arg_closed
1222         {
1223                 $$ = check_scheme_arg (parser, @4, $4, $3, $2);
1224         }
1225         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed bare_number_closed
1226         {
1227                 $$ = check_scheme_arg (parser, @4, $4, $3, $2);
1228         }
1229         ;
1230
1231 function_arglist_nonbackup:
1232         function_arglist_nonbackup_common
1233         | EXPECT_OPTIONAL EXPECT_SCM function_arglist embedded_scm_arg
1234         {
1235                 $$ = check_scheme_arg (parser, @4, $4, $3, $2);
1236         }
1237         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed bare_number
1238         {
1239                 $$ = check_scheme_arg (parser, @4, $4, $3, $2);
1240         }
1241         ;
1242
1243 function_arglist_keep:
1244         function_arglist_common
1245         | function_arglist_backup
1246         ;
1247
1248 function_arglist_closed_keep:
1249         function_arglist_closed_common
1250         | function_arglist_backup
1251         ;
1252
1253 function_arglist_backup:
1254         EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep embedded_scm_arg_closed
1255         {
1256                 if (scm_is_true (scm_call_1 ($2, $4)))
1257                 {
1258                         $$ = scm_cons ($4, $3);
1259                 } else {
1260                         $$ = scm_cons (loc_on_music (@3, $1), $3);
1261                         MYBACKUP (SCM_IDENTIFIER, $4, @4);
1262                 }
1263         }
1264         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep post_event_nofinger
1265         {
1266                 if (scm_is_true (scm_call_1 ($2, $4)))
1267                 {
1268                         $$ = scm_cons ($4, $3);
1269                 } else {
1270                         $$ = scm_cons (loc_on_music (@3, $1), $3);
1271                         MYBACKUP (EVENT_IDENTIFIER, $4, @4);
1272                 }
1273         }
1274         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep lyric_element
1275         {
1276                 // There is no point interpreting a lyrics string as
1277                 // an event, since we don't allow music possibly
1278                 // followed by durations or postevent into closed
1279                 // music, and we only accept closed music in optional
1280                 // arguments at the moment.  If this changes, more
1281                 // complex schemes might become interesting here as
1282                 // well: see how we do this at the mandatory argument
1283                 // point.
1284                 if (scm_is_true (scm_call_1 ($2, $4)))
1285                         $$ = scm_cons ($4, $3);
1286                 else {
1287                         $$ = scm_cons (loc_on_music (@3, $1), $3);
1288                         MYBACKUP (LYRICS_STRING, $4, @4);
1289                 }
1290         }
1291         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep UNSIGNED
1292         {
1293                 if (scm_is_true (scm_call_1 ($2, $4)))
1294                 {
1295                         $$ = $3;
1296                         MYREPARSE (@4, $2, UNSIGNED, $4);
1297                 } else {
1298                         $$ = scm_cons (loc_on_music (@3, $1), $3);
1299                         MYBACKUP (UNSIGNED, $4, @4);
1300                 }
1301         }
1302         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep REAL
1303         {
1304                 if (scm_is_true (scm_call_1 ($2, $4)))
1305                 {
1306                         $$ = $3;
1307                         MYREPARSE (@4, $2, REAL, $4);
1308                 } else {
1309                         $$ = scm_cons (loc_on_music (@3, $1), $3);
1310                         MYBACKUP (REAL, $4, @4);
1311                 }
1312         }
1313         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep NUMBER_IDENTIFIER
1314         {
1315                 if (scm_is_true (scm_call_1 ($2, $4)))
1316                 {
1317                         $$ = scm_cons ($4, $3);
1318                 } else {
1319                         $$ = scm_cons (loc_on_music (@3, $1), $3);
1320                         MYBACKUP (NUMBER_IDENTIFIER, $4, @4);
1321                 }
1322         }
1323         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep FRACTION
1324         {
1325                 if (scm_is_true (scm_call_1 ($2, $4)))
1326                 {
1327                         $$ = scm_cons ($4, $3);
1328                 } else {
1329                         $$ = scm_cons (loc_on_music (@3, $1), $3);
1330                         MYBACKUP (FRACTION, $4, @4);
1331                 }
1332         }
1333         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep '-' UNSIGNED
1334         {
1335                 SCM n = scm_difference ($5, SCM_UNDEFINED);
1336                 if (scm_is_true (scm_call_1 ($2, n))) {
1337                         $$ = $3;
1338                         MYREPARSE (@5, $2, REAL, n);
1339                 } else {
1340                         Music *t = MY_MAKE_MUSIC ("FingeringEvent", @5);
1341                         t->set_property ("digit", $5);
1342                         $$ = t->unprotect ();
1343                         if (scm_is_true (scm_call_1 ($2, $$)))
1344                                 $$ = scm_cons ($$, $3);
1345                         else {
1346                                 $$ = scm_cons (loc_on_music (@3, $1), $3);
1347                                 MYBACKUP (UNSIGNED, $5, @5);
1348                                 parser->lexer_->push_extra_token ('-');
1349                         }
1350                 }
1351                 
1352         }
1353         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep '-' REAL
1354         {
1355                 SCM n = scm_difference ($5, SCM_UNDEFINED);
1356                 if (scm_is_true (scm_call_1 ($2, n))) {
1357                         MYREPARSE (@5, $2, REAL, n);
1358                         $$ = $3;
1359                 } else {
1360                         MYBACKUP (REAL, n, @5);
1361                 }
1362         }
1363         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep '-' NUMBER_IDENTIFIER
1364         {
1365                 SCM n = scm_difference ($5, SCM_UNDEFINED);
1366                 if (scm_is_true (scm_call_1 ($2, n))) {
1367                         $$ = scm_cons (n, $3);
1368                 } else {
1369                         MYBACKUP (NUMBER_IDENTIFIER, n, @5);
1370                 }
1371         }
1372         | EXPECT_OPTIONAL EXPECT_PITCH function_arglist_keep pitch_also_in_chords
1373         {
1374                 $$ = scm_cons ($4, $3);
1375         }
1376         | EXPECT_OPTIONAL EXPECT_DURATION function_arglist_closed_keep duration_length
1377         {
1378                 $$ = scm_cons ($4, $3);
1379         }
1380         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup BACKUP
1381         {
1382                 $$ = scm_cons ($1, $3);
1383                 MYBACKUP(0, SCM_UNDEFINED, @3);
1384         }
1385         | function_arglist_backup REPARSE embedded_scm_arg_closed
1386         {
1387                 $$ = check_scheme_arg (parser, @3,
1388                                        $3, $1, $2);
1389         }
1390         | function_arglist_backup REPARSE bare_number
1391         {
1392                 $$ = check_scheme_arg (parser, @3,
1393                                        $3, $1, $2);
1394         }
1395         ;
1396
1397 function_arglist:
1398         function_arglist_common
1399         | function_arglist_nonbackup
1400         ;
1401
1402 function_arglist_common:
1403         function_arglist_bare
1404         | EXPECT_SCM function_arglist_optional embedded_scm_arg
1405         {
1406                 $$ = check_scheme_arg (parser, @3,
1407                                        $3, $2, $1);
1408         }
1409         | EXPECT_SCM function_arglist_closed_optional bare_number
1410         {
1411                 $$ = check_scheme_arg (parser, @3,
1412                                        $3, $2, $1);
1413         }
1414         | EXPECT_SCM function_arglist_closed_optional FRACTION
1415         {
1416                 $$ = check_scheme_arg (parser, @3,
1417                                        $3, $2, $1);
1418         }
1419         | EXPECT_SCM function_arglist_closed_optional post_event_nofinger
1420         {
1421                 $$ = check_scheme_arg (parser, @3,
1422                                        $3, $2, $1);
1423         }
1424         | function_arglist_common_minus
1425         | function_arglist_common_lyric
1426         ;
1427
1428 function_arglist_common_lyric:
1429         EXPECT_SCM function_arglist_optional lyric_element
1430         {
1431                 // We check how the predicate thinks about a lyrics
1432                 // event or about a markup.  If it accepts neither, we
1433                 // backup the original token.  Otherwise we commit to
1434                 // taking the token.  Depending on what the predicate
1435                 // is willing to accept, we interpret as a string, as
1436                 // a lyric event, or ambiguously (meaning that if
1437                 // something looking like a duration or post event
1438                 // follows, we take the event, otherwise the string).
1439                 SCM lyric_event = MAKE_SYNTAX ("lyric-event", @3, $3,
1440                                                parser->default_duration_.smobbed_copy ());
1441                 if (scm_is_true (scm_call_1 ($1, $3)))
1442                         if (scm_is_true (scm_call_1 ($1, lyric_event)))
1443                         {
1444                                 $$ = $2;
1445                                 MYREPARSE (@3, $1, LYRICS_STRING, $3);
1446                         } else {
1447                                 $$ = scm_cons ($3, $2);
1448                         }
1449                 else if (scm_is_true (scm_call_1 ($1, lyric_event)))
1450                 {
1451                         $$ = $2;
1452                         MYREPARSE (@3, $1, LYRIC_ELEMENT, $3);
1453                 } else {
1454                         // This is going to flag a syntax error, we
1455                         // know the predicate to be false.
1456                         check_scheme_arg (parser, @3,
1457                                           $3, $2, $1);
1458                 }
1459         }
1460         | function_arglist_common_lyric REPARSE lyric_element_arg
1461         {
1462                 // This should never be false
1463                 $$ = check_scheme_arg (parser, @3,
1464                                        $3, $1, $2);
1465         }
1466         ;
1467
1468 function_arglist_common_minus:
1469         EXPECT_SCM function_arglist_closed_optional '-' UNSIGNED
1470         {
1471                 SCM n = scm_difference ($4, SCM_UNDEFINED);
1472                 if (scm_is_true (scm_call_1 ($1, n))) {
1473                         $$ = $2;
1474                         MYREPARSE (@4, $1, REAL, n);
1475                 } else {
1476                         Music *t = MY_MAKE_MUSIC ("FingeringEvent", @4);
1477                         t->set_property ("digit", $4);
1478                         $$ = t->unprotect ();
1479                         if (scm_is_true (scm_call_1 ($1, $$)))
1480                                 $$ = scm_cons ($$, $2);
1481                         else
1482                                 $$ = check_scheme_arg (parser, @3, n, $2, $1);
1483                 }
1484                 
1485         }
1486         | EXPECT_SCM function_arglist_closed_optional '-' REAL
1487         {
1488                 $$ = $2;
1489                 SCM n = scm_difference ($4, SCM_UNDEFINED);
1490                 MYREPARSE (@4, $1, REAL, n);
1491         }
1492         | EXPECT_SCM function_arglist_closed_optional '-' NUMBER_IDENTIFIER
1493         {
1494                 SCM n = scm_difference ($4, SCM_UNDEFINED);
1495                 $$ = check_scheme_arg (parser, @4, n, $2, $1);
1496         }
1497         | function_arglist_common_minus REPARSE bare_number
1498         {
1499                 $$ = check_scheme_arg (parser, @3, $3, $1, $2);
1500         }
1501         ;
1502
1503 function_arglist_closed:
1504         function_arglist_closed_common
1505         | function_arglist_closed_nonbackup
1506         ;
1507
1508 function_arglist_closed_common:
1509         function_arglist_bare
1510         | EXPECT_SCM function_arglist_optional embedded_scm_arg_closed
1511         {
1512                 $$ = check_scheme_arg (parser, @3,
1513                                        $3, $2, $1);
1514         }
1515         | EXPECT_SCM function_arglist_closed_optional bare_number
1516         {
1517                 $$ = check_scheme_arg (parser, @3,
1518                                        $3, $2, $1);
1519         }
1520         | EXPECT_SCM function_arglist_closed_optional '-' UNSIGNED
1521         {
1522                 SCM n = scm_difference ($4, SCM_UNDEFINED);
1523                 if (scm_is_true (scm_call_1 ($1, n))) {
1524                         $$ = scm_cons (n, $2);
1525                 } else {
1526                         Music *t = MY_MAKE_MUSIC ("FingeringEvent", @4);
1527                         t->set_property ("digit", $4);
1528                         $$ = t->unprotect ();
1529                         if (scm_is_true (scm_call_1 ($1, $$)))
1530                                 $$ = scm_cons ($$, $2);
1531                         else
1532                                 $$ = check_scheme_arg (parser, @3, n, $2, $1);
1533                 }
1534                 
1535         }
1536         | EXPECT_SCM function_arglist_closed_optional '-' REAL
1537         {
1538                 $$ = check_scheme_arg (parser, @3,
1539                                        scm_difference ($4, SCM_UNDEFINED),
1540                                        $2, $1);
1541         }
1542         | EXPECT_SCM function_arglist_closed_optional '-' NUMBER_IDENTIFIER
1543         {
1544                 $$ = check_scheme_arg (parser, @3,
1545                                        scm_difference ($4, SCM_UNDEFINED),
1546                                        $2, $1);
1547         }
1548         | EXPECT_SCM function_arglist_closed_optional post_event_nofinger
1549         {
1550                 $$ = check_scheme_arg (parser, @3,
1551                                        $3, $2, $1);
1552         }
1553         | EXPECT_SCM function_arglist_closed_optional FRACTION
1554         {
1555                 $$ = check_scheme_arg (parser, @3,
1556                                        $3, $2, $1);
1557         }
1558         | EXPECT_SCM function_arglist_optional lyric_element
1559         {
1560                 $$ = check_scheme_arg (parser, @3,
1561                                        $3, $2, $1);
1562         }
1563         ;
1564
1565 function_arglist_optional:
1566         function_arglist_keep %prec FUNCTION_ARGLIST
1567         | function_arglist_backup BACKUP
1568         | EXPECT_OPTIONAL EXPECT_PITCH function_arglist_optional
1569         {
1570                 $$ = scm_cons ($1, $3);
1571         }
1572         | EXPECT_OPTIONAL EXPECT_DURATION function_arglist_optional
1573         {
1574                 $$ = scm_cons ($1, $3);
1575         }
1576         ;
1577
1578 function_arglist_closed_optional:
1579         function_arglist_closed_keep %prec FUNCTION_ARGLIST
1580         | function_arglist_backup BACKUP
1581         | EXPECT_OPTIONAL EXPECT_PITCH function_arglist_closed_optional
1582         {
1583                 $$ = scm_cons ($1, $3);
1584         }
1585         | EXPECT_OPTIONAL EXPECT_DURATION function_arglist_closed_optional
1586         {
1587                 $$ = scm_cons ($1, $3);
1588         }
1589         ;
1590
1591 embedded_scm_closed:
1592         embedded_scm_bare
1593         | scm_function_call_closed
1594         ;
1595
1596 embedded_scm_arg_closed:
1597         embedded_scm_bare_arg
1598         | scm_function_call_closed
1599         | closed_music
1600         ;
1601
1602 scm_function_call_closed:
1603         SCM_FUNCTION function_arglist_closed {
1604                 $$ = MAKE_SYNTAX ("music-function", @$,
1605                                          $1, $2);
1606         } %prec FUNCTION_ARGLIST
1607         ;
1608
1609 function_arglist_bare:
1610         EXPECT_NO_MORE_ARGS {
1611                 $$ = SCM_EOL;
1612         }
1613         | EXPECT_PITCH function_arglist_optional pitch_also_in_chords {
1614                 $$ = scm_cons ($3, $2);
1615         }
1616         | EXPECT_DURATION function_arglist_closed_optional duration_length {
1617                 $$ = scm_cons ($3, $2);
1618         }
1619         | EXPECT_OPTIONAL EXPECT_PITCH function_arglist_skip DEFAULT {
1620                 $$ = scm_cons ($1, $3);
1621         }
1622         | EXPECT_OPTIONAL EXPECT_DURATION function_arglist_skip DEFAULT {
1623                 $$ = scm_cons ($1, $3);
1624         }
1625         | EXPECT_OPTIONAL EXPECT_SCM function_arglist_skip DEFAULT {
1626                 $$ = scm_cons ($1, $3);
1627         }
1628         ;
1629
1630 music_function_call:
1631         MUSIC_FUNCTION function_arglist {
1632                 $$ = MAKE_SYNTAX ("music-function", @$,
1633                                          $1, $2);
1634         }
1635         ;
1636
1637
1638 optional_id:
1639         /**/ { $$ = SCM_EOL; }
1640         | '=' simple_string {
1641                 $$ = $2;
1642         }
1643         ;
1644
1645 complex_music:
1646         music_function_call
1647         | repeated_music                { $$ = $1; }
1648         | re_rhythmed_music     { $$ = $1; }
1649         | complex_music_prefix music
1650         {
1651                 $$ = FINISH_MAKE_SYNTAX ($1, @$, $2);
1652         }
1653         ;
1654
1655 complex_music_prefix:
1656         CONTEXT simple_string optional_id optional_context_mod {
1657                 Context_mod *ctxmod = unsmob_context_mod ($4);
1658                 SCM mods = SCM_EOL;
1659                 if (ctxmod)
1660                         mods = ctxmod->get_mods ();
1661                 $$ = START_MAKE_SYNTAX ("context-specification", $2, $3, mods, SCM_BOOL_F);
1662         }
1663         | NEWCONTEXT simple_string optional_id optional_context_mod {
1664                 Context_mod *ctxmod = unsmob_context_mod ($4);
1665                 SCM mods = SCM_EOL;
1666                 if (ctxmod)
1667                         mods = ctxmod->get_mods ();
1668                 $$ = START_MAKE_SYNTAX ("context-specification", $2, $3, mods, SCM_BOOL_T);
1669         }
1670         ;
1671
1672 mode_changed_music:
1673         mode_changing_head grouped_music_list {
1674                 if ($1 == ly_symbol2scm ("chords"))
1675                 {
1676                   $$ = MAKE_SYNTAX ("unrelativable-music", @$, $2);
1677                 }
1678                 else
1679                 {
1680                   $$ = $2;
1681                 }
1682                 parser->lexer_->pop_state ();
1683         }
1684         | mode_changing_head_with_context optional_context_mod grouped_music_list {
1685                 Context_mod *ctxmod = unsmob_context_mod ($2);
1686                 SCM mods = SCM_EOL;
1687                 if (ctxmod)
1688                         mods = ctxmod->get_mods ();
1689                 $$ = MAKE_SYNTAX ("context-specification", @$, $1, SCM_EOL, mods, SCM_BOOL_T, $3);
1690                 if ($1 == ly_symbol2scm ("ChordNames"))
1691                 {
1692                   $$ = MAKE_SYNTAX ("unrelativable-music", @$, $$);
1693                 }
1694                 parser->lexer_->pop_state ();
1695         }
1696         ;
1697
1698 mode_changing_head:
1699         NOTEMODE {
1700                 SCM nn = parser->lexer_->lookup_identifier ("pitchnames");
1701                 parser->lexer_->push_note_state (nn);
1702
1703                 $$ = ly_symbol2scm ("notes");
1704         }
1705         | DRUMMODE
1706                 {
1707                 SCM nn = parser->lexer_->lookup_identifier ("drumPitchNames");
1708                 parser->lexer_->push_note_state (nn);
1709
1710                 $$ = ly_symbol2scm ("drums");
1711         }
1712         | FIGUREMODE {
1713                 parser->lexer_->push_figuredbass_state ();
1714
1715                 $$ = ly_symbol2scm ("figures");
1716         }
1717         | CHORDMODE {
1718                 SCM nn = parser->lexer_->lookup_identifier ("chordmodifiers");
1719                 parser->lexer_->chordmodifier_tab_ = alist_to_hashq (nn);
1720                 nn = parser->lexer_->lookup_identifier ("pitchnames");
1721                 parser->lexer_->push_chord_state (nn);
1722                 $$ = ly_symbol2scm ("chords");
1723
1724         }
1725         | LYRICMODE
1726                 { parser->lexer_->push_lyric_state ();
1727                 $$ = ly_symbol2scm ("lyrics");
1728         }
1729         ;
1730
1731 mode_changing_head_with_context:
1732         DRUMS {
1733                 SCM nn = parser->lexer_->lookup_identifier ("drumPitchNames");
1734                 parser->lexer_->push_note_state (nn);
1735
1736                 $$ = ly_symbol2scm ("DrumStaff");
1737         }
1738         | FIGURES {
1739                 parser->lexer_->push_figuredbass_state ();
1740
1741                 $$ = ly_symbol2scm ("FiguredBass");
1742         }
1743         | CHORDS {
1744                 SCM nn = parser->lexer_->lookup_identifier ("chordmodifiers");
1745                 parser->lexer_->chordmodifier_tab_ = alist_to_hashq (nn);
1746                 nn = parser->lexer_->lookup_identifier ("pitchnames");
1747                 parser->lexer_->push_chord_state (nn);
1748                 $$ = ly_symbol2scm ("ChordNames");
1749         }
1750         | LYRICS
1751                 { parser->lexer_->push_lyric_state ();
1752                 $$ = ly_symbol2scm ("Lyrics");
1753         }
1754         ;
1755
1756 new_lyrics:
1757         ADDLYRICS { parser->lexer_->push_lyric_state (); }
1758         /*cont */
1759         composite_music {
1760         /* Can also use music at the expensive of two S/Rs similar to
1761            \repeat \alternative */
1762                 parser->lexer_->pop_state ();
1763
1764                 $$ = scm_cons ($3, SCM_EOL);
1765         }
1766         | new_lyrics ADDLYRICS {
1767                 parser->lexer_->push_lyric_state ();
1768         } composite_music {
1769                 parser->lexer_->pop_state ();
1770                 $$ = scm_cons ($4, $1);
1771         }
1772         ;
1773
1774 re_rhythmed_music:
1775         composite_music new_lyrics {
1776                 $$ = MAKE_SYNTAX ("add-lyrics", @$, $1, scm_reverse_x ($2, SCM_EOL));
1777         } %prec COMPOSITE
1778         | LYRICSTO simple_string {
1779                 parser->lexer_->push_lyric_state ();
1780         } music {
1781                 parser->lexer_->pop_state ();
1782                 $$ = MAKE_SYNTAX ("lyric-combine", @$, $2, $4);
1783         }
1784         ;
1785
1786 context_change:
1787         CHANGE STRING '=' STRING  {
1788                 $$ = MAKE_SYNTAX ("context-change", @$, scm_string_to_symbol ($2), $4);
1789         }
1790         ;
1791
1792
1793 property_path_revved:
1794         embedded_scm_closed {
1795                 $$ = scm_cons ($1, SCM_EOL);
1796         }
1797         | property_path_revved embedded_scm_closed {
1798                 $$ = scm_cons ($2, $1);
1799         }
1800         ;
1801
1802 property_path:
1803         property_path_revved  {
1804                 $$ = scm_reverse_x ($1, SCM_EOL);
1805         }
1806         ;
1807
1808 property_operation:
1809         STRING '=' scalar {
1810                 $$ = scm_list_3 (ly_symbol2scm ("assign"),
1811                         scm_string_to_symbol ($1), $3);
1812         }
1813         | UNSET simple_string {
1814                 $$ = scm_list_2 (ly_symbol2scm ("unset"),
1815                         scm_string_to_symbol ($2));
1816         }
1817         | OVERRIDE simple_string property_path '=' scalar {
1818                 $$ = scm_append (scm_list_2 (scm_list_3 (ly_symbol2scm ("push"),
1819                                                         scm_string_to_symbol ($2), $5),
1820                                              $3));
1821         }
1822         | REVERT simple_string embedded_scm {
1823                 $$ = scm_list_3 (ly_symbol2scm ("pop"),
1824                         scm_string_to_symbol ($2), $3);
1825         }
1826         ;
1827
1828 context_def_mod:
1829         CONSISTS { $$ = ly_symbol2scm ("consists"); }
1830         | REMOVE { $$ = ly_symbol2scm ("remove"); }
1831
1832         | ACCEPTS { $$ = ly_symbol2scm ("accepts"); }
1833         | DEFAULTCHILD { $$ = ly_symbol2scm ("default-child"); }
1834         | DENIES { $$ = ly_symbol2scm ("denies"); }
1835
1836         | ALIAS { $$ = ly_symbol2scm ("alias"); }
1837         | TYPE { $$ = ly_symbol2scm ("translator-type"); }
1838         | DESCRIPTION { $$ = ly_symbol2scm ("description"); }
1839         | NAME { $$ = ly_symbol2scm ("context-name"); }
1840         ;
1841
1842 context_mod:
1843         property_operation { $$ = $1; }
1844         | context_def_mod STRING {
1845                 $$ = scm_list_2 ($1, $2);
1846         }
1847         | context_def_mod embedded_scm
1848         {
1849                 if (!scm_is_string ($2)
1850                     && ly_symbol2scm ("consists") != $1
1851                     && ly_symbol2scm ("remove") != $1)
1852                 {
1853                         $$ = SCM_EOL;
1854                         parser->parser_error (@1, _ ("only \\consists and \\remove take non-string argument."));
1855                 }
1856                 else
1857                 {
1858                         $$ = scm_list_2 ($1, $2);
1859                 }
1860         }
1861         ;
1862
1863 context_prop_spec:
1864         simple_string {
1865                 if (!is_regular_identifier ($1))
1866                 {
1867                         @$.error (_("Grob name should be alphanumeric"));
1868                 }
1869
1870                 $$ = scm_list_2 (ly_symbol2scm ("Bottom"),
1871                         scm_string_to_symbol ($1));
1872         }
1873         | simple_string '.' simple_string {
1874                 $$ = scm_list_2 (scm_string_to_symbol ($1),
1875                         scm_string_to_symbol ($3));
1876         }
1877         ;
1878
1879 simple_music_property_def:
1880         OVERRIDE context_prop_spec property_path '=' scalar {
1881                 $$ = scm_append (scm_list_2 (scm_list_n (scm_car ($2),
1882                                 ly_symbol2scm ("OverrideProperty"),
1883                                 scm_cadr ($2),
1884                                 $5, SCM_UNDEFINED),
1885                                 $3));
1886         }
1887         | REVERT context_prop_spec embedded_scm {
1888                 $$ = scm_list_4 (scm_car ($2),
1889                         ly_symbol2scm ("RevertProperty"),
1890                         scm_cadr ($2),
1891                         $3);
1892         }
1893         | SET context_prop_spec '=' scalar {
1894                 $$ = scm_list_4 (scm_car ($2),
1895                         ly_symbol2scm ("PropertySet"),
1896                         scm_cadr ($2),
1897                         $4);
1898         }
1899         | UNSET context_prop_spec {
1900                 $$ = scm_list_3 (scm_car ($2),
1901                         ly_symbol2scm ("PropertyUnset"),
1902                         scm_cadr ($2));
1903         }
1904         ;
1905
1906 music_property_def:
1907         simple_music_property_def {
1908                 $$ = LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant ("property-operation"), scm_cons2 (parser->self_scm (), make_input (@$), $1));
1909         }
1910         ;
1911
1912 string:
1913         STRING {
1914                 $$ = $1;
1915         }
1916         | full_markup
1917         | string '+' string {
1918                 if (!scm_is_string ($1)) {
1919                         parser->parser_error (@1, (_ ("simple string expected")));
1920                         $1 = scm_string (SCM_EOL);
1921                 }
1922                 if (!scm_is_string ($3)) {
1923                         parser->parser_error (@3, (_ ("simple string expected")));
1924                         $3 = scm_string (SCM_EOL);
1925                 }
1926                 $$ = scm_string_append (scm_list_2 ($1, $3));
1927         }
1928         ;
1929
1930 simple_string: STRING {
1931                 $$ = $1;
1932         }
1933         | LYRICS_STRING {
1934                 $$ = $1;
1935         }
1936         | embedded_scm_bare
1937         {
1938                 if (scm_is_string ($1)) {
1939                         $$ = $1;
1940                 } else {
1941                         parser->parser_error (@1, (_ ("simple string expected")));
1942                         $$ = scm_string (SCM_EOL);
1943                 }
1944         }
1945         ;
1946
1947 scalar:
1948         embedded_scm_arg
1949         | bare_number
1950         | FRACTION
1951         | lyric_element
1952         ;
1953
1954 scalar_closed:
1955         embedded_scm_arg_closed
1956         | bare_number
1957         | FRACTION
1958         | lyric_element
1959         ;
1960
1961
1962 event_chord:
1963         simple_element post_events {
1964                 // Let the rhythmic music iterator sort this mess out.
1965                 if (scm_is_pair ($2)) {
1966                         $$ = make_music_from_simple (parser, @1, $1);
1967                         if (unsmob_music ($$))
1968                                 unsmob_music ($$)->set_property ("articulations",
1969                                                                  scm_reverse_x ($2, SCM_EOL));
1970                         else
1971                                 parser->parser_error (@1, _("music expected"));
1972                 }
1973         }
1974         | simple_chord_elements post_events     {
1975                 SCM elts = ly_append2 ($1, scm_reverse_x ($2, SCM_EOL));
1976
1977                 Input i;
1978                 /* why is this giving wrong start location? -ns
1979                  * i = @$; */
1980                 i.set_location (@1, @2);
1981                 $$ = MAKE_SYNTAX ("event-chord", i, elts);
1982         }
1983         | CHORD_REPETITION optional_notemode_duration post_events {
1984                 Input i;
1985                 i.set_location (@1, @3);
1986                 $$ = MAKE_SYNTAX ("repetition-chord", i,
1987                                   $2, scm_reverse_x ($3, SCM_EOL));
1988         }
1989         | MULTI_MEASURE_REST optional_notemode_duration post_events {
1990                 Input i;
1991                 i.set_location (@1, @3);
1992                 $$ = MAKE_SYNTAX ("multi-measure-rest", i, $2,
1993                                   scm_reverse_x ($3, SCM_EOL));
1994         }
1995         | command_element
1996         | note_chord_element
1997         ;
1998
1999
2000 note_chord_element:
2001         chord_body optional_notemode_duration post_events
2002         {
2003                 Music *m = unsmob_music ($1);
2004                 SCM dur = unsmob_duration ($2)->smobbed_copy ();
2005                 SCM es = m->get_property ("elements");
2006                 SCM postevs = scm_reverse_x ($3, SCM_EOL);
2007
2008                 for (SCM s = es; scm_is_pair (s); s = scm_cdr (s))
2009                   unsmob_music (scm_car (s))->set_property ("duration", dur);
2010                 es = ly_append2 (es, postevs);
2011
2012                 m-> set_property ("elements", es);
2013                 m->set_spot (@$);
2014                 $$ = m->self_scm ();
2015         }
2016         ;
2017
2018 chord_body:
2019         ANGLE_OPEN chord_body_elements ANGLE_CLOSE
2020         {
2021                 $$ = MAKE_SYNTAX ("event-chord", @$, scm_reverse_x ($2, SCM_EOL));
2022         }
2023         ;
2024
2025 chord_body_elements:
2026         /* empty */             { $$ = SCM_EOL; }
2027         | chord_body_elements chord_body_element {
2028                 if (!SCM_UNBNDP ($2))
2029                         $$ = scm_cons ($2, $1);
2030         }
2031         ;
2032
2033 chord_body_element:
2034         pitch exclamations questions octave_check post_events
2035         {
2036                 bool q = to_boolean ($3);
2037                 bool ex = to_boolean ($2);
2038                 SCM check = $4;
2039                 SCM post = $5;
2040
2041                 Music *n = MY_MAKE_MUSIC ("NoteEvent", @$);
2042                 n->set_property ("pitch", $1);
2043                 if (q)
2044                         n->set_property ("cautionary", SCM_BOOL_T);
2045                 if (ex || q)
2046                         n->set_property ("force-accidental", SCM_BOOL_T);
2047
2048                 if (scm_is_pair (post)) {
2049                         SCM arts = scm_reverse_x (post, SCM_EOL);
2050                         n->set_property ("articulations", arts);
2051                 }
2052                 if (scm_is_number (check))
2053                 {
2054                         int q = scm_to_int (check);
2055                         n->set_property ("absolute-octave", scm_from_int (q-1));
2056                 }
2057
2058                 $$ = n->unprotect ();
2059         }
2060         | DRUM_PITCH post_events {
2061                 Music *n = MY_MAKE_MUSIC ("NoteEvent", @$);
2062                 n->set_property ("drum-type", $1);
2063
2064                 if (scm_is_pair ($2)) {
2065                         SCM arts = scm_reverse_x ($2, SCM_EOL);
2066                         n->set_property ("articulations", arts);
2067                 }
2068                 $$ = n->unprotect ();
2069         }
2070         | music_function_chord_body
2071         {
2072                 Music *m = unsmob_music ($1);
2073
2074                 while (m && m->is_mus_type ("music-wrapper-music")) {
2075                         $$ = m->get_property ("element");
2076                         m = unsmob_music ($$);
2077                 }
2078
2079                 if (!(m && m->is_mus_type ("rhythmic-event"))) {
2080                         parser->parser_error (@$, _ ("not a rhythmic event"));
2081                         $$ = SCM_UNDEFINED;
2082                 }
2083         }
2084         ;
2085
2086 music_function_chord_body:
2087         music_function_call
2088         | MUSIC_IDENTIFIER
2089         ;
2090
2091 // Event functions may only take closed arglists, otherwise it would
2092 // not be clear whether a following postevent should be associated
2093 // with the last argument of the event function or with the expression
2094 // for which the function call acts itself as event.
2095
2096 music_function_call_closed:
2097         MUSIC_FUNCTION function_arglist_closed {
2098                 $$ = MAKE_SYNTAX ("music-function", @$,
2099                                          $1, $2);
2100         }
2101         ;
2102
2103 event_function_event:
2104         EVENT_FUNCTION function_arglist_closed {
2105                 $$ = MAKE_SYNTAX ("music-function", @$,
2106                                          $1, $2);
2107         }
2108         ;
2109
2110 command_element:
2111         command_event {
2112                 $$ = $1;
2113         }
2114         | E_BRACKET_OPEN {
2115                 Music *m = MY_MAKE_MUSIC ("LigatureEvent", @$);
2116                 m->set_property ("span-direction", scm_from_int (START));
2117                 $$ = m->unprotect();
2118         }
2119         | E_BRACKET_CLOSE {
2120                 Music *m = MY_MAKE_MUSIC ("LigatureEvent", @$);
2121                 m->set_property ("span-direction", scm_from_int (STOP));
2122                 $$ = m->unprotect ();
2123         }
2124         | E_BACKSLASH {
2125                 $$ = MAKE_SYNTAX ("voice-separator", @$);
2126         }
2127         | '|'      {
2128                 SCM pipe = parser->lexer_->lookup_identifier ("pipeSymbol");
2129
2130                 Music *m = unsmob_music (pipe);
2131                 if (m)
2132                 {
2133                         m = m->clone ();
2134                         m->set_spot (@$);
2135                         $$ = m->unprotect ();
2136                 }
2137                 else
2138                         $$ = MAKE_SYNTAX ("bar-check", @$);
2139
2140         }
2141         ;
2142
2143 command_event:
2144         E_TILDE {
2145                 $$ = MY_MAKE_MUSIC ("PesOrFlexaEvent", @$)->unprotect ();
2146         }
2147         | tempo_event {
2148                 $$ = $1;
2149         }
2150         ;
2151
2152
2153 post_events:
2154         /* empty */ {
2155                 $$ = SCM_EOL;
2156         }
2157         | post_events post_event {
2158                 unsmob_music ($2)->set_spot (@2);
2159                 $$ = scm_cons ($2, $$);
2160         }
2161         ;
2162
2163 post_event_nofinger:
2164         direction_less_event {
2165                 $$ = $1;
2166         }
2167         | script_dir music_function_call_closed {
2168                 $$ = $2;
2169                 if (!SCM_UNBNDP ($1))
2170                 {
2171                         unsmob_music ($$)->set_property ("direction", $1);
2172                 }
2173         }
2174         | HYPHEN {
2175                 if (!parser->lexer_->is_lyric_state ())
2176                         parser->parser_error (@1, _ ("have to be in Lyric mode for lyrics"));
2177                 $$ = MY_MAKE_MUSIC ("HyphenEvent", @$)->unprotect ();
2178         }
2179         | EXTENDER {
2180                 if (!parser->lexer_->is_lyric_state ())
2181                         parser->parser_error (@1, _ ("have to be in Lyric mode for lyrics"));
2182                 $$ = MY_MAKE_MUSIC ("ExtenderEvent", @$)->unprotect ();
2183         }
2184         | script_dir direction_reqd_event {
2185                 if (!SCM_UNBNDP ($1))
2186                 {
2187                         Music *m = unsmob_music ($2);
2188                         m->set_property ("direction", $1);
2189                 }
2190                 $$ = $2;
2191         }
2192         | script_dir direction_less_event {
2193                 if (!SCM_UNBNDP ($1))
2194                 {
2195                         Music *m = unsmob_music ($2);
2196                         m->set_property ("direction", $1);
2197                 }
2198                 $$ = $2;
2199         }
2200         | '^' fingering
2201         {
2202                 $$ = $2;
2203                 unsmob_music ($$)->set_property ("direction", scm_from_int (UP));
2204         }
2205         | '_' fingering
2206         {
2207                 $$ = $2;
2208                 unsmob_music ($$)->set_property ("direction", scm_from_int (DOWN));
2209         }                       
2210         ;
2211
2212 post_event:
2213         post_event_nofinger
2214         | '-' fingering {
2215                 $$ = $2;
2216         }
2217         ;
2218
2219 string_number_event:
2220         E_UNSIGNED {
2221                 Music *s = MY_MAKE_MUSIC ("StringNumberEvent", @$);
2222                 s->set_property ("string-number", $1);
2223                 $$ = s->unprotect ();
2224         }
2225         ;
2226
2227 direction_less_char:
2228         '['  {
2229                 $$ = ly_symbol2scm ("bracketOpenSymbol");
2230         }
2231         | ']'  {
2232                 $$ = ly_symbol2scm ("bracketCloseSymbol");
2233         }
2234         | '~'  {
2235                 $$ = ly_symbol2scm ("tildeSymbol");
2236         }
2237         | '('  {
2238                 $$ = ly_symbol2scm ("parenthesisOpenSymbol");
2239         }
2240         | ')'  {
2241                 $$ = ly_symbol2scm ("parenthesisCloseSymbol");
2242         }
2243         | E_EXCLAMATION  {
2244                 $$ = ly_symbol2scm ("escapedExclamationSymbol");
2245         }
2246         | E_OPEN  {
2247                 $$ = ly_symbol2scm ("escapedParenthesisOpenSymbol");
2248         }
2249         | E_CLOSE  {
2250                 $$ = ly_symbol2scm ("escapedParenthesisCloseSymbol");
2251         }
2252         | E_ANGLE_CLOSE  {
2253                 $$ = ly_symbol2scm ("escapedBiggerSymbol");
2254         }
2255         | E_ANGLE_OPEN  {
2256                 $$ = ly_symbol2scm ("escapedSmallerSymbol");
2257         }
2258         ;
2259
2260 direction_less_event:
2261         direction_less_char {
2262                 SCM predefd = parser->lexer_->lookup_identifier_symbol ($1);
2263                 Music *m = 0;
2264                 if (unsmob_music (predefd))
2265                 {
2266                         m = unsmob_music (predefd)->clone ();
2267                         m->set_spot (@$);
2268                 }
2269                 else
2270                 {
2271                         m = MY_MAKE_MUSIC ("Music", @$);
2272                 }
2273                 $$ = m->unprotect ();
2274         }
2275         | string_number_event
2276         | EVENT_IDENTIFIER      {
2277                 $$ = $1;
2278         }
2279         | tremolo_type  {
2280                Music *a = MY_MAKE_MUSIC ("TremoloEvent", @$);
2281                a->set_property ("tremolo-type", $1);
2282                $$ = a->unprotect ();
2283         }
2284         | event_function_event  
2285         ;
2286
2287 direction_reqd_event:
2288         gen_text_def {
2289                 $$ = $1;
2290         }
2291         | script_abbreviation {
2292                 SCM s = parser->lexer_->lookup_identifier ("dash" + ly_scm2string ($1));
2293                 Music *a = MY_MAKE_MUSIC ("ArticulationEvent", @$);
2294                 if (scm_is_string (s))
2295                         a->set_property ("articulation-type", s);
2296                 else parser->parser_error (@1, _ ("expecting string as script definition"));
2297                 $$ = a->unprotect ();
2298         }
2299         ;
2300
2301 octave_check:
2302         /**/ { $$ = SCM_EOL; }
2303         | '=' quotes { $$ = $2; }
2304         ;
2305
2306 quotes:
2307         /* empty */
2308         {
2309                 $$ = SCM_INUM0;
2310         }
2311         | sub_quotes
2312         | sup_quotes
2313         ;
2314
2315 sup_quotes:
2316         '\'' {
2317                 $$ = scm_from_int (1);
2318         }
2319         | sup_quotes '\'' {
2320                 $$ = scm_oneplus ($1);
2321         }
2322         ;
2323
2324 sub_quotes:
2325         ',' {
2326                 $$ = scm_from_int (-1);
2327         }
2328         | sub_quotes ',' {
2329                 $$ = scm_oneminus ($1);
2330         }
2331         ;
2332
2333 steno_pitch:
2334         NOTENAME_PITCH quotes {
2335                 if (!scm_is_eq (SCM_INUM0, $2))
2336                 {
2337                         Pitch p = *unsmob_pitch ($1);
2338                         p = p.transposed (Pitch (scm_to_int ($2),0,0));
2339                         $$ = p.smobbed_copy ();
2340                 }
2341         }
2342         ;
2343
2344 /*
2345 ugh. duplication
2346 */
2347
2348 steno_tonic_pitch:
2349         TONICNAME_PITCH quotes {
2350                 if (!scm_is_eq (SCM_INUM0, $2))
2351                 {
2352                         Pitch p = *unsmob_pitch ($1);
2353                         p = p.transposed (Pitch (scm_to_int ($2),0,0));
2354                         $$ = p.smobbed_copy ();
2355                 }
2356         }
2357         ;
2358
2359 pitch:
2360         steno_pitch
2361         | PITCH_IDENTIFIER
2362         ;
2363
2364 pitch_also_in_chords:
2365         pitch
2366         | steno_tonic_pitch
2367         ;
2368
2369 gen_text_def:
2370         full_markup {
2371                 Music *t = MY_MAKE_MUSIC ("TextScriptEvent", @$);
2372                 t->set_property ("text", $1);
2373                 $$ = t->unprotect ();
2374         }
2375         | STRING {
2376                 Music *t = MY_MAKE_MUSIC ("TextScriptEvent", @$);
2377                 t->set_property ("text",
2378                         make_simple_markup ($1));
2379                 $$ = t->unprotect ();
2380         }
2381         | LYRICS_STRING {
2382                 Music *t = MY_MAKE_MUSIC ("TextScriptEvent", @$);
2383                 t->set_property ("text",
2384                         make_simple_markup ($1));
2385                 $$ = t->unprotect ();
2386         }
2387         | embedded_scm_bare
2388         {
2389                 Music *m = unsmob_music ($1);
2390                 if (m && m->is_mus_type ("post-event"))
2391                         $$ = $1;
2392                 else if (Text_interface::is_markup ($1)) {
2393                         Music *t = MY_MAKE_MUSIC ("TextScriptEvent", @$);
2394                         t->set_property ("text", $1);
2395                         $$ = t->unprotect ();
2396                 } else
2397                         parser->parser_error (@1, _ ("not an articulation"));
2398         }
2399         ;
2400
2401 fingering:
2402         UNSIGNED {
2403                 Music *t = MY_MAKE_MUSIC ("FingeringEvent", @$);
2404                 t->set_property ("digit", $1);
2405                 $$ = t->unprotect ();
2406         }
2407         ;
2408
2409 script_abbreviation:
2410         '^'             {
2411                 $$ = scm_from_locale_string ("Hat");
2412         }
2413         | '+'           {
2414                 $$ = scm_from_locale_string ("Plus");
2415         }
2416         | '-'           {
2417                 $$ = scm_from_locale_string ("Dash");
2418         }
2419         | '|'           {
2420                 $$ = scm_from_locale_string ("Bar");
2421         }
2422         | ANGLE_CLOSE   {
2423                 $$ = scm_from_locale_string ("Larger");
2424         }
2425         | '.'           {
2426                 $$ = scm_from_locale_string ("Dot");
2427         }
2428         | '_' {
2429                 $$ = scm_from_locale_string ("Underscore");
2430         }
2431         ;
2432
2433 script_dir:
2434         '_'     { $$ = scm_from_int (DOWN); }
2435         | '^'   { $$ = scm_from_int (UP); }
2436         | '-'   { $$ = SCM_UNDEFINED; }
2437         ;
2438
2439 duration_length:
2440         multiplied_duration {
2441                 $$ = $1;
2442         }
2443         ;
2444
2445 maybe_notemode_duration:
2446         {
2447                 $$ = SCM_UNDEFINED;
2448         }
2449         | multiplied_duration   {
2450                 $$ = $1;
2451                 parser->default_duration_ = *unsmob_duration ($$);
2452         }
2453 ;
2454
2455
2456 optional_notemode_duration:
2457         maybe_notemode_duration
2458         {
2459                 if (SCM_UNBNDP ($$))
2460                         $$ = parser->default_duration_.smobbed_copy ();
2461         }
2462         ;
2463
2464 steno_duration:
2465         UNSIGNED dots           {
2466                 int len = 0;
2467                 int n = scm_to_int ($1);
2468                 if (!is_duration (n))
2469                         parser->parser_error (@1, _f ("not a duration: %d", n));
2470                 else
2471                         len = intlog2 (n);
2472
2473                 $$ = Duration (len, scm_to_int ($2)).smobbed_copy ();
2474         }
2475         | DURATION_IDENTIFIER dots      {
2476                 Duration *d = unsmob_duration ($1);
2477                 Duration k (d->duration_log (),
2478                             d->dot_count () + scm_to_int ($2));
2479                 k = k.compressed (d->factor ());
2480                 scm_remember_upto_here_1 ($1);
2481                 $$ = k.smobbed_copy ();
2482         }
2483         ;
2484
2485 multiplied_duration:
2486         steno_duration {
2487                 $$ = $1;
2488         }
2489         | multiplied_duration '*' UNSIGNED {
2490                 $$ = unsmob_duration ($$)->compressed (scm_to_int ($3)).smobbed_copy ();
2491         }
2492         | multiplied_duration '*' FRACTION {
2493                 Rational  m (scm_to_int (scm_car ($3)), scm_to_int (scm_cdr ($3)));
2494
2495                 $$ = unsmob_duration ($$)->compressed (m).smobbed_copy ();
2496         }
2497         ;
2498
2499 dots:
2500         /* empty */     {
2501                 $$ = SCM_INUM0;
2502         }
2503         | dots '.' {
2504                 $$ = scm_oneplus ($1);
2505         }
2506         ;
2507
2508 tremolo_type:
2509         ':'     {
2510                 $$ = SCM_INUM0;
2511         }
2512         | ':' UNSIGNED {
2513                 int n = scm_to_int ($2);
2514                 if (!is_duration (n))
2515                         parser->parser_error (@2, _f ("not a duration: %d", n));
2516                 $$ = $2;
2517         }
2518         ;
2519
2520 bass_number:
2521         UNSIGNED { $$ = $1; }
2522         | STRING { $$ = $1; }
2523         | full_markup { $$ = $1; }
2524         | embedded_scm_bare
2525         {
2526                 // as an integer, it needs to be non-negative, and otherwise
2527                 // it needs to be suitable as a markup.
2528                 if (scm_is_integer ($1)
2529                     ? scm_is_true (scm_negative_p ($1))
2530                     : !Text_interface::is_markup ($1))
2531                 {
2532                         parser->parser_error (@1, _ ("bass number expected"));
2533                         $$ = SCM_INUM0;
2534                 }
2535         }
2536         ;
2537
2538 figured_bass_alteration:
2539         '-'     { $$ = ly_rational2scm (FLAT_ALTERATION); }
2540         | '+'   { $$ = ly_rational2scm (SHARP_ALTERATION); }
2541         | '!'   { $$ = scm_from_int (0); }
2542         ;
2543
2544 bass_figure:
2545         FIGURE_SPACE {
2546                 Music *bfr = MY_MAKE_MUSIC ("BassFigureEvent", @$);
2547                 $$ = bfr->unprotect ();
2548         }
2549         | bass_number  {
2550                 Music *bfr = MY_MAKE_MUSIC ("BassFigureEvent", @$);
2551                 $$ = bfr->self_scm ();
2552
2553                 if (scm_is_number ($1))
2554                         bfr->set_property ("figure", $1);
2555                 else if (Text_interface::is_markup ($1))
2556                         bfr->set_property ("text", $1);
2557
2558                 bfr->unprotect ();
2559         }
2560         | bass_figure ']' {
2561                 $$ = $1;
2562                 unsmob_music ($1)->set_property ("bracket-stop", SCM_BOOL_T);
2563         }
2564         | bass_figure figured_bass_alteration {
2565                 Music *m = unsmob_music ($1);
2566                 if (scm_to_double ($2)) {
2567                         SCM salter = m->get_property ("alteration");
2568                         SCM alter = scm_is_number (salter) ? salter : scm_from_int (0);
2569                         m->set_property ("alteration",
2570                                          scm_sum (alter, $2));
2571                 } else {
2572                         m->set_property ("alteration", scm_from_int (0));
2573                 }
2574         }
2575         | bass_figure figured_bass_modification  {
2576                 Music *m = unsmob_music ($1);
2577                 if ($2 == ly_symbol2scm ("plus"))
2578                         {
2579                         m->set_property ("augmented", SCM_BOOL_T);
2580                         }
2581                 else if ($2 == ly_symbol2scm ("slash"))
2582                         {
2583                         m->set_property ("diminished", SCM_BOOL_T);
2584                         }
2585                 else if ($2 == ly_symbol2scm ("exclamation"))
2586                         {
2587                         m->set_property ("no-continuation", SCM_BOOL_T);
2588                         }
2589                 else if ($2 == ly_symbol2scm ("backslash"))
2590                         {
2591                         m->set_property ("augmented-slash", SCM_BOOL_T);
2592                         }
2593         }
2594         ;
2595
2596
2597 figured_bass_modification:
2598         E_PLUS          {
2599                 $$ = ly_symbol2scm ("plus");
2600         }
2601         | E_EXCLAMATION {
2602                 $$ = ly_symbol2scm ("exclamation");
2603         }
2604         | '/'           {
2605                 $$ = ly_symbol2scm ("slash");
2606         }
2607         | E_BACKSLASH {
2608                 $$ = ly_symbol2scm ("backslash");
2609         }
2610         ;
2611
2612 br_bass_figure:
2613         bass_figure {
2614                 $$ = $1;
2615         }
2616         | '[' bass_figure {
2617                 $$ = $2;
2618                 unsmob_music ($$)->set_property ("bracket-start", SCM_BOOL_T);
2619         }
2620         ;
2621
2622 figure_list:
2623         /**/            {
2624                 $$ = SCM_EOL;
2625         }
2626         | figure_list br_bass_figure {
2627                 $$ = scm_cons ($2, $1);
2628         }
2629         ;
2630
2631 figure_spec:
2632         FIGURE_OPEN figure_list FIGURE_CLOSE {
2633                 $$ = scm_reverse_x ($2, SCM_EOL);
2634         }
2635         ;
2636
2637
2638 optional_rest:
2639         /**/   { $$ = SCM_BOOL_F; }
2640         | REST { $$ = SCM_BOOL_T; }
2641         ;
2642
2643 simple_element:
2644         pitch exclamations questions octave_check maybe_notemode_duration optional_rest {
2645                 if (!parser->lexer_->is_note_state ())
2646                         parser->parser_error (@1, _ ("have to be in Note mode for notes"));
2647                 if (!SCM_UNBNDP ($2)
2648                     || !SCM_UNBNDP ($3)
2649                     || scm_is_number ($4)
2650                     || !SCM_UNBNDP ($5)
2651                     || scm_is_true ($6))
2652                 {
2653                         Music *n = 0;
2654                         if (scm_is_true ($6))
2655                                 n = MY_MAKE_MUSIC ("RestEvent", @$);
2656                         else
2657                                 n = MY_MAKE_MUSIC ("NoteEvent", @$);
2658                         
2659                         n->set_property ("pitch", $1);
2660                         if (SCM_UNBNDP ($5))
2661                                 n->set_property ("duration",
2662                                                  parser->default_duration_.smobbed_copy ());
2663                         else
2664                                 n->set_property ("duration", $5);
2665                         
2666                         if (scm_is_number ($4))
2667                         {
2668                                 int q = scm_to_int ($4);
2669                                 n->set_property ("absolute-octave", scm_from_int (q-1));
2670                         }
2671                         
2672                         if (to_boolean ($3))
2673                                 n->set_property ("cautionary", SCM_BOOL_T);
2674                         if (to_boolean ($2) || to_boolean ($3))
2675                                 n->set_property ("force-accidental", SCM_BOOL_T);
2676                         
2677                         $$ = n->unprotect ();
2678                 }
2679         }
2680         | DRUM_PITCH optional_notemode_duration {
2681                 Music *n = MY_MAKE_MUSIC ("NoteEvent", @$);
2682                 n->set_property ("duration", $2);
2683                 n->set_property ("drum-type", $1);
2684
2685                 $$ = n->unprotect ();
2686         }
2687         | RESTNAME optional_notemode_duration           {
2688                 Music *ev = 0;
2689                 if (ly_scm2string ($1) == "s") {
2690                         /* Space */
2691                         ev = MY_MAKE_MUSIC ("SkipEvent", @$);
2692                   }
2693                 else {
2694                         ev = MY_MAKE_MUSIC ("RestEvent", @$);
2695
2696                     }
2697                 ev->set_property ("duration", $2);
2698                 $$ = ev->unprotect ();
2699         }
2700         ;
2701
2702 simple_chord_elements:
2703         new_chord {
2704                 if (!parser->lexer_->is_chord_state ())
2705                         parser->parser_error (@1, _ ("have to be in Chord mode for chords"));
2706                 $$ = $1;
2707         }
2708         | figure_spec optional_notemode_duration {
2709                 for (SCM s = $1; scm_is_pair (s); s = scm_cdr (s))
2710                 {
2711                         unsmob_music (scm_car (s))->set_property ("duration", $2);
2712                 }
2713                 $$ = $1;
2714         }
2715         ;
2716
2717 lyric_element:
2718         lyric_markup {
2719                 $$ = $1;
2720         }
2721         | LYRICS_STRING {
2722                 $$ = $1;
2723         }
2724         ;
2725
2726 lyric_element_arg:
2727         lyric_element
2728         | lyric_element multiplied_duration post_events {
2729                 $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
2730                 if (scm_is_pair ($3))
2731                         unsmob_music ($$)->set_property
2732                                 ("articulations", scm_reverse_x ($3, SCM_EOL));
2733         }
2734         | lyric_element post_event post_events {
2735                 $$ = MAKE_SYNTAX ("lyric-event", @$, $1,
2736                                   parser->default_duration_.smobbed_copy ());
2737                 unsmob_music ($$)->set_property
2738                         ("articulations", scm_cons ($2, scm_reverse_x ($3, SCM_EOL)));
2739         }
2740         | LYRIC_ELEMENT optional_notemode_duration post_events {
2741                 $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
2742                 if (scm_is_pair ($3))
2743                         unsmob_music ($$)->set_property
2744                                 ("articulations", scm_reverse_x ($3, SCM_EOL));
2745         }
2746         ;
2747
2748
2749 lyric_element_music:
2750         lyric_element optional_notemode_duration post_events {
2751                 $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
2752                 if (scm_is_pair ($3))
2753                         unsmob_music ($$)->set_property
2754                                 ("articulations", scm_reverse_x ($3, SCM_EOL));
2755         }
2756         ;
2757
2758 new_chord:
2759         steno_tonic_pitch optional_notemode_duration   {
2760                 $$ = make_chord_elements (@$, $1, $2, SCM_EOL);
2761         }
2762         | steno_tonic_pitch optional_notemode_duration chord_separator chord_items {
2763                 SCM its = scm_reverse_x ($4, SCM_EOL);
2764                 $$ = make_chord_elements (@$, $1, $2, scm_cons ($3, its));
2765         }
2766         ;
2767
2768 chord_items:
2769         /**/ {
2770                 $$ = SCM_EOL;
2771         }
2772         | chord_items chord_item {
2773                 $$ = scm_cons ($2, $$);
2774         }
2775         ;
2776
2777 chord_separator:
2778         CHORD_COLON {
2779                 $$ = ly_symbol2scm ("chord-colon");
2780         }
2781         | CHORD_CARET {
2782                 $$ = ly_symbol2scm ("chord-caret");
2783         }
2784         | CHORD_SLASH steno_tonic_pitch {
2785                 $$ = scm_list_2 (ly_symbol2scm ("chord-slash"), $2);
2786         }
2787         | CHORD_BASS steno_tonic_pitch {
2788                 $$ = scm_list_2 (ly_symbol2scm ("chord-bass"), $2);
2789         }
2790         ;
2791
2792 chord_item:
2793         chord_separator {
2794                 $$ = $1;
2795         }
2796         | step_numbers {
2797                 $$ = scm_reverse_x ($1, SCM_EOL);
2798         }
2799         | CHORD_MODIFIER  {
2800                 $$ = $1;
2801         }
2802         ;
2803
2804 step_numbers:
2805         step_number { $$ = scm_cons ($1, SCM_EOL); }
2806         | step_numbers '.' step_number {
2807                 $$ = scm_cons ($3, $$);
2808         }
2809         ;
2810
2811 step_number:
2812         UNSIGNED {
2813                 $$ = make_chord_step ($1, 0);
2814         }
2815         | UNSIGNED '+' {
2816                 $$ = make_chord_step ($1, SHARP_ALTERATION);
2817         }
2818         | UNSIGNED CHORD_MINUS {
2819                 $$ = make_chord_step ($1, FLAT_ALTERATION);
2820         }
2821         ;
2822
2823 tempo_range:
2824         UNSIGNED {
2825                 $$ = $1;
2826         }
2827         | UNSIGNED '~' UNSIGNED {
2828                 $$ = scm_cons ($1, $3);
2829         }
2830         ;
2831
2832 /*
2833         UTILITIES
2834
2835 TODO: should deprecate in favor of Scheme?
2836
2837  */
2838 number_expression:
2839         number_expression '+' number_term {
2840                 $$ = scm_sum ($1, $3);
2841         }
2842         | number_expression '-' number_term {
2843                 $$ = scm_difference ($1, $3);
2844         }
2845         | number_term
2846         ;
2847
2848 number_term:
2849         number_factor {
2850                 $$ = $1;
2851         }
2852         | number_factor '*' number_factor {
2853                 $$ = scm_product ($1, $3);
2854         }
2855         | number_factor '/' number_factor {
2856                 $$ = scm_divide ($1, $3);
2857         }
2858         ;
2859
2860 number_factor:
2861         '-'  number_factor { /* %prec UNARY_MINUS */
2862                 $$ = scm_difference ($2, SCM_UNDEFINED);
2863         }
2864         | bare_number
2865         ;
2866
2867
2868 bare_number:
2869         bare_number_closed
2870         | UNSIGNED NUMBER_IDENTIFIER    {
2871                 $$ = scm_product ($1, $2);
2872         }
2873         | REAL NUMBER_IDENTIFIER        {
2874                 $$ = scm_product ($1, $2);
2875         }
2876         ;
2877
2878 bare_number_closed:
2879         UNSIGNED
2880         | REAL
2881         | NUMBER_IDENTIFIER
2882         ;
2883
2884 unsigned_number:
2885         UNSIGNED
2886         | NUMBER_IDENTIFIER
2887         ;
2888
2889 exclamations:
2890                 { $$ = SCM_UNDEFINED; }
2891         | exclamations '!'
2892         {
2893                 if (SCM_UNBNDP ($1))
2894                         $$ = SCM_BOOL_T;
2895                 else
2896                         $$ = scm_not ($1);
2897         }
2898         ;
2899
2900 questions:
2901         { $$ = SCM_UNDEFINED; }
2902         | questions '?'
2903         {
2904                 if (SCM_UNBNDP ($1))
2905                         $$ = SCM_BOOL_T;
2906                 else
2907                         $$ = scm_not ($1);
2908         }
2909         ;
2910
2911 /*
2912 This should be done more dynamically if possible.
2913 */
2914
2915 lyric_markup:
2916         LYRIC_MARKUP
2917                 { parser->lexer_->push_markup_state (); }
2918         markup_top {
2919                 $$ = $3;
2920                 parser->lexer_->pop_state ();
2921         }
2922         ;
2923
2924 full_markup_list:
2925         MARKUPLIST
2926                 { parser->lexer_->push_markup_state (); }
2927         markup_list {
2928                 $$ = $3;
2929                 parser->lexer_->pop_state ();
2930         }
2931         ;
2932
2933 full_markup:
2934         MARKUP
2935                 { parser->lexer_->push_markup_state (); }
2936         markup_top {
2937                 $$ = $3;
2938                 parser->lexer_->pop_state ();
2939         }
2940         ;
2941
2942 markup_top:
2943         markup_list {
2944                 $$ = scm_list_2 (ly_lily_module_constant ("line-markup"),  $1);
2945         }
2946         | markup_head_1_list simple_markup      {
2947                 $$ = scm_car (scm_call_2 (ly_lily_module_constant ("map-markup-command-list"), $1, scm_list_1 ($2)));
2948         }
2949         | simple_markup {
2950                 $$ = $1;
2951         }
2952         ;
2953
2954 markup_scm:
2955         embedded_scm_bare
2956         {
2957                 if (Text_interface::is_markup ($1))
2958                         MYBACKUP (MARKUP_IDENTIFIER, $1, @1);
2959                 else if (Text_interface::is_markup_list ($1))
2960                         MYBACKUP (MARKUPLIST_IDENTIFIER, $1, @1);
2961                 else {
2962                         parser->parser_error (@1, _ ("not a markup"));
2963                         MYBACKUP (MARKUP_IDENTIFIER, scm_string (SCM_EOL), @1);
2964                 }
2965         } BACKUP
2966         ;
2967                         
2968
2969 markup_list:
2970         markup_composed_list {
2971                 $$ = $1;
2972         }
2973         | markup_braced_list {
2974                 $$ = $1;
2975         }
2976         | markup_command_list {
2977                 $$ = scm_list_1 ($1);
2978         }
2979         | markup_scm MARKUPLIST_IDENTIFIER
2980         {
2981                 $$ = $2;
2982         }
2983         ;
2984
2985 markup_composed_list:
2986         markup_head_1_list markup_braced_list {
2987                 $$ = scm_call_2 (ly_lily_module_constant ("map-markup-command-list"), $1, $2);
2988
2989         }
2990         ;
2991
2992 markup_braced_list:
2993         '{' markup_braced_list_body '}' {
2994                 $$ = scm_reverse_x ($2, SCM_EOL);
2995         }
2996         ;
2997
2998 markup_braced_list_body:
2999         /* empty */     {  $$ = SCM_EOL; }
3000         | markup_braced_list_body markup {
3001                 $$ = scm_cons ($2, $1);
3002         }
3003         | markup_braced_list_body markup_list {
3004                 $$ = scm_reverse_x ($2, $1);
3005         }
3006         ;
3007
3008 markup_command_list:
3009         MARKUP_LIST_FUNCTION markup_command_list_arguments {
3010           $$ = scm_cons ($1, scm_reverse_x($2, SCM_EOL));
3011         }
3012         ;
3013
3014 markup_command_basic_arguments:
3015         EXPECT_MARKUP_LIST markup_command_list_arguments markup_list {
3016           $$ = scm_cons ($3, $2);
3017         }
3018         | EXPECT_SCM markup_command_list_arguments embedded_scm_closed {
3019           $$ = check_scheme_arg (parser, @3, $3, $2, $1);
3020         }
3021         | EXPECT_NO_MORE_ARGS {
3022           $$ = SCM_EOL;
3023         }
3024         ;
3025
3026 markup_command_list_arguments:
3027         markup_command_basic_arguments { $$ = $1; }
3028         | EXPECT_MARKUP markup_command_list_arguments markup {
3029           $$ = scm_cons ($3, $2);
3030         }
3031         ;
3032
3033 markup_head_1_item:
3034         MARKUP_FUNCTION EXPECT_MARKUP markup_command_list_arguments {
3035           $$ = scm_cons ($1, scm_reverse_x ($3, SCM_EOL));
3036         }
3037         ;
3038
3039 markup_head_1_list:
3040         markup_head_1_item      {
3041                 $$ = scm_list_1 ($1);
3042         }
3043         | markup_head_1_list markup_head_1_item {
3044                 $$ = scm_cons ($2, $1);
3045         }
3046         ;
3047
3048 simple_markup:
3049         STRING {
3050                 $$ = make_simple_markup ($1);
3051         }
3052         | SCORE {
3053                 SCM nn = parser->lexer_->lookup_identifier ("pitchnames");
3054                 parser->lexer_->push_note_state (nn);
3055         } '{' score_body '}' {
3056                 $$ = scm_list_2 (ly_lily_module_constant ("score-markup"), $4);
3057                 parser->lexer_->pop_state ();
3058         }
3059         | MARKUP_FUNCTION markup_command_basic_arguments {
3060                 $$ = scm_cons ($1, scm_reverse_x ($2, SCM_EOL));
3061         }
3062         | markup_scm MARKUP_IDENTIFIER
3063         {
3064                 $$ = $2;
3065         }
3066         ;
3067
3068 markup:
3069         markup_head_1_list simple_markup        {
3070                 SCM mapper = ly_lily_module_constant ("map-markup-command-list");
3071                 $$ = scm_car (scm_call_2 (mapper, $1, scm_list_1 ($2)));
3072         }
3073         | simple_markup {
3074                 $$ = $1;
3075         }
3076         ;
3077
3078 %%
3079
3080 void
3081 Lily_parser::set_yydebug (bool x)
3082 {
3083         yydebug = x;
3084 }
3085
3086 SCM
3087 Lily_parser::do_yyparse ()
3088 {
3089         SCM retval = SCM_UNDEFINED;
3090         yyparse (this, &retval);
3091         return retval;
3092 }
3093
3094
3095
3096
3097
3098 /*
3099
3100 It is a little strange to have this function in this file, but
3101 otherwise, we have to import music classes into the lexer.
3102
3103 */
3104 int
3105 Lily_lexer::try_special_identifiers (SCM *destination, SCM sid)
3106 {
3107         if (unsmob_book (sid)) {
3108                 Book *book =  unsmob_book (sid)->clone ();
3109                 *destination = book->self_scm ();
3110                 book->unprotect ();
3111
3112                 return BOOK_IDENTIFIER;
3113         } else if (scm_is_number (sid)) {
3114                 *destination = sid;
3115                 return NUMBER_IDENTIFIER;
3116         } else if (unsmob_context_def (sid)) {
3117                 Context_def *def= unsmob_context_def (sid)->clone ();
3118
3119                 *destination = def->self_scm ();
3120                 def->unprotect ();
3121
3122                 return CONTEXT_DEF_IDENTIFIER;
3123         } else if (unsmob_context_mod (sid)) {
3124                 *destination = unsmob_context_mod (sid)->smobbed_copy ();
3125
3126                 return CONTEXT_MOD_IDENTIFIER;
3127         } else if (unsmob_score (sid)) {
3128                 Score *score = new Score (*unsmob_score (sid));
3129                 *destination = score->self_scm ();
3130
3131                 score->unprotect ();
3132                 return SCORE_IDENTIFIER;
3133         } else if (Music *mus = unsmob_music (sid)) {
3134                 mus = mus->clone ();
3135                 *destination = mus->self_scm ();
3136                 unsmob_music (*destination)->
3137                         set_property ("origin", make_input (last_input_));
3138
3139                 bool is_event = mus->is_mus_type ("post-event");
3140                 mus->unprotect ();
3141                 return is_event ? EVENT_IDENTIFIER : MUSIC_IDENTIFIER;
3142         } else if (unsmob_pitch (sid)) {
3143                 *destination = unsmob_pitch (sid)->smobbed_copy ();
3144                 return PITCH_IDENTIFIER;
3145         } else if (unsmob_duration (sid)) {
3146                 *destination = unsmob_duration (sid)->smobbed_copy ();
3147                 return DURATION_IDENTIFIER;
3148         } else if (unsmob_output_def (sid)) {
3149                 Output_def *p = unsmob_output_def (sid);
3150                 p = p->clone ();
3151
3152                 *destination = p->self_scm ();
3153                 p->unprotect ();
3154                 return OUTPUT_DEF_IDENTIFIER;
3155         }
3156
3157         return -1;
3158 }
3159
3160 SCM
3161 get_next_unique_context_id ()
3162 {
3163         return scm_from_locale_string ("$uniqueContextId");
3164 }
3165
3166
3167 SCM
3168 get_next_unique_lyrics_context_id ()
3169 {
3170         static int new_context_count;
3171         char s[128];
3172         snprintf (s, sizeof (s)-1, "uniqueContext%d", new_context_count++);
3173         return scm_from_locale_string (s);
3174 }
3175
3176 SCM check_scheme_arg (Lily_parser *parser, Input loc,
3177                       SCM arg, SCM args, SCM pred)
3178 {
3179         args = scm_cons (arg, args);
3180         if (scm_is_true (scm_call_1 (pred, arg)))
3181                 return args;
3182         scm_set_cdr_x (scm_last_pair (args), SCM_EOL);
3183         MAKE_SYNTAX ("argument-error", loc, scm_length (args), pred, arg);
3184         scm_set_cdr_x (scm_last_pair (args), SCM_BOOL_F);
3185         return args;
3186 }
3187
3188 SCM loc_on_music (Input loc, SCM arg)
3189 {
3190         if (Music *m = unsmob_music (arg))
3191         {
3192                 m = m->clone ();
3193                 m->set_spot (loc);
3194                 return m->unprotect ();
3195         }
3196         return arg;
3197 }
3198
3199 bool
3200 is_regular_identifier (SCM id)
3201 {
3202   string str = ly_scm2string (id);
3203   char const *s = str.c_str ();
3204
3205   bool v = true;
3206 #if 0
3207   isalpha (*s);
3208   s++;
3209 #endif
3210   while (*s && v)
3211    {
3212         v = v && isalnum (*s);
3213         s++;
3214    }
3215   return v;
3216 }
3217
3218 SCM
3219 make_music_from_simple (Lily_parser *parser, Input loc, SCM simple)
3220 {
3221         if (unsmob_music (simple))
3222                 return simple;
3223         if (parser->lexer_->is_note_state ()) {
3224                 Music *n = MY_MAKE_MUSIC ("NoteEvent", loc);
3225                 n->set_property ("duration", parser->default_duration_.smobbed_copy ());
3226                 if (scm_is_symbol (simple))
3227                         n->set_property ("drum-type", simple);
3228                 else if (unsmob_pitch (simple))
3229                         n->set_property ("pitch", simple);
3230                 else {
3231                         n->unprotect ();
3232                         return simple;
3233                 }
3234                 return n->unprotect ();
3235         } else if (parser->lexer_->is_lyric_state ()) {
3236                 if (Text_interface::is_markup (simple))
3237                         return MAKE_SYNTAX ("lyric-event", loc, simple,
3238                                             parser->default_duration_.smobbed_copy ());
3239         } else if (parser->lexer_->is_chord_state ()) {
3240                 if (unsmob_pitch (simple))
3241                         return make_chord_elements (loc, simple,
3242                                                     parser->default_duration_.smobbed_copy (),
3243                                                     SCM_EOL);
3244         }
3245         return simple;
3246 }
3247
3248 Music *
3249 make_music_with_input (SCM name, Input where)
3250 {
3251        Music *m = make_music_by_name (name);
3252        m->set_spot (where);
3253        return m;
3254 }
3255
3256 SCM
3257 make_simple_markup (SCM a)
3258 {
3259         return a;
3260 }
3261
3262 bool
3263 is_duration (int t)
3264 {
3265   return t && t == 1 << intlog2 (t);
3266 }
3267
3268 SCM
3269 make_chord_step (SCM step_scm, Rational alter)
3270 {
3271         int step = scm_to_int (step_scm);
3272
3273         if (step == 7)
3274                 alter += FLAT_ALTERATION;
3275
3276         while (step < 0)
3277                 step += 7;
3278         Pitch m ((step -1) / 7, (step - 1) % 7, alter);
3279         return m.smobbed_copy ();
3280 }
3281
3282
3283 SCM
3284 make_chord_elements (Input loc, SCM pitch, SCM dur, SCM modification_list)
3285 {
3286         SCM chord_ctor = ly_lily_module_constant ("construct-chord-elements");
3287         SCM res = scm_call_3 (chord_ctor, pitch, dur, modification_list);
3288         for (SCM s = res; scm_is_pair (s); s = scm_cdr (s))
3289         {
3290                 unsmob_music (scm_car (s))->set_spot (loc);
3291         }
3292         return res;
3293 }
3294
3295 int
3296 yylex (YYSTYPE *s, YYLTYPE *loc, Lily_parser *parser)
3297 {
3298         Lily_lexer *lex = parser->lexer_;
3299
3300         lex->lexval_ = s;
3301         lex->lexloc_ = loc;
3302         lex->prepare_for_next_token ();
3303         return lex->yylex ();
3304 }