]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/parser.yy
Merge remote-tracking branch 'origin/master' into translation
[lilypond.git] / lily / parser.yy
index de47a599a2faef9b7cbabb8344087ce8b26b84a3..0804ce575b59f240ff3b43fcd1487ad7c9511fe0 100644 (file)
@@ -224,14 +224,15 @@ SCM get_next_unique_lyrics_context_id ();
 
 static Music *make_music_with_input (SCM name, Input where);
 SCM check_scheme_arg (Lily_parser *parser, Input loc,
-                     SCM arg, SCM args, SCM pred);
+                     SCM arg, SCM args, SCM pred, SCM disp = SCM_UNDEFINED);
 SCM make_music_from_simple (Lily_parser *parser, Input loc, SCM pitch);
 SCM loc_on_music (Input loc, SCM arg);
 SCM make_chord_elements (Input loc, SCM pitch, SCM dur, SCM modification_list);
 SCM make_chord_step (SCM step, Rational alter);
 SCM make_simple_markup (SCM a);
 bool is_duration (int t);
-bool is_regular_identifier (SCM id);
+bool is_regular_identifier (SCM id, bool multiple=false);
+SCM try_string_variants (SCM pred, SCM str);
 int yylex (YYSTYPE *s, YYLTYPE *loc, Lily_parser *parser);
 
 %}
@@ -374,11 +375,12 @@ If we give names, Bison complains.
 %token OUTPUT_DEF_IDENTIFIER
 %token REAL
 %token RESTNAME
+%token SCM_ARG
 %token SCM_FUNCTION
 %token SCM_IDENTIFIER
 %token SCM_TOKEN
-%token SCORE_IDENTIFIER
 %token STRING
+%token SYMBOL_LIST
 %token TONICNAME_PITCH
 
 %left '-' '+'
@@ -492,7 +494,7 @@ embedded_scm_active:
        ;
 
 embedded_scm_bare_arg:
-       STRING
+       SCM_ARG
        | SCM_TOKEN
        {
                $$ = parser->lexer_->eval_scm_token ($1);
@@ -643,7 +645,8 @@ context_def_spec_body:
                unsmob_context_def ($$)->origin ()->set_spot (@$);
        }
        | context_def_spec_body context_mod {
-               unsmob_context_def ($$)->add_context_mod ($2);
+               if (!SCM_UNBNDP ($2))
+                       unsmob_context_def ($$)->add_context_mod ($2);
        }
        | context_def_spec_body context_modification {
                 Context_def *td = unsmob_context_def ($$);
@@ -826,8 +829,16 @@ score_body:
 
                unsmob_score ($$)->origin ()->set_spot (@$);
        }
-       | SCORE_IDENTIFIER {
+       | embedded_scm_active {
+               Score *score;
+               if (unsmob_score ($1))
+                       score = new Score (*unsmob_score ($1));
+               else {
+                       score = new Score;
+                       parser->parser_error (@1, _("score expected"));
+               }
                unsmob_score ($$)->origin ()->set_spot (@$);
+               $$ = score->unprotect ();
        }
        | score_body
        {
@@ -1113,7 +1124,8 @@ context_mod_list:
             $$ = Context_mod ().smobbed_copy ();
         }
         | context_mod_list context_mod  {
-                 unsmob_context_mod ($1)->add_context_mod ($2);
+               if (!SCM_UNBNDP ($2))
+                       unsmob_context_mod ($1)->add_context_mod ($2);
         }
         | context_mod_list CONTEXT_MOD_IDENTIFIER {
                  Context_mod *md = unsmob_context_mod ($2);
@@ -1156,6 +1168,34 @@ grouped_music_list:
  MUSIC_FUNCTION EXPECT_PITCH EXPECT_SCM EXPECT_SCM EXPECT_NO_MORE_ARGS
 and this rule returns the reversed list of arguments. */
 
+/* Function argument lists come in a number of flavors.  Whenever
+ * LilyPond has to pick between different flavors, the decision is
+ * either made because of tokens it has already seen, or it is
+ * postponed until tokens suitable for making the decision come up.
+ * For postponing decisions, it may be necessary that the competing
+ * rules are written in a way making them compatible until a decision
+ * can be made.  Sometimes this is done by putting common traits into
+ * a separate "common" rule set.
+ *
+ * function_arglist: a full argument list.  Optional arguments at the
+ * end of the list can only be skipped by writing \default in their
+ * place.
+ *
+ * function_arglist_backup: an argument list ending in an optional
+ * argument that may be skipped depending on its predicate.
+ *
+ * function_arglist_skip: an argument list _not_ ending in an optional
+ * argument that is actually taken.
+ *
+ * function_arglist_nonbackup: an argument list ending in an optional
+ * argument that may not be skipped because it is in end position and
+ * has not been shortcircuited with \default.
+ *
+ * function_arglist* / function_arglist_closed*: The closed variants
+ * don't end in simple music expressions that might still accept
+ * things like a duration or a postevent.
+ */
+
 function_arglist_skip:
        function_arglist_common
        | EXPECT_OPTIONAL EXPECT_PITCH function_arglist_skip
@@ -1196,11 +1236,8 @@ function_arglist_nonbackup_common:
                else {
                        Music *t = MY_MAKE_MUSIC ("FingeringEvent", @5);
                        t->set_property ("digit", $5);
-                       $$ = t->unprotect ();
-                       if (scm_is_true (scm_call_1 ($2, $$)))
-                               $$ = scm_cons ($$, $3);
-                       else
-                               $$ = check_scheme_arg (parser, @4, n, $3, $2);
+                       $$ = check_scheme_arg (parser, @4, t->unprotect (),
+                                              $3, $2, n);
                }
                
        }
@@ -1224,29 +1261,156 @@ function_arglist_closed_nonbackup:
        {
                $$ = check_scheme_arg (parser, @4, $4, $3, $2);
        }
-       | EXPECT_OPTIONAL EXPECT_SCM function_arglist SCM_IDENTIFIER
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed bare_number_closed
        {
                $$ = check_scheme_arg (parser, @4, $4, $3, $2);
        }
-       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed bare_number_closed
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist SCM_IDENTIFIER
+       {
+               $$ = check_scheme_arg (parser, @4,
+                                      try_string_variants ($2, $4),
+                                      $3, $2, $4);
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist STRING
+       {
+               $$ = check_scheme_arg (parser, @4,
+                                      try_string_variants ($2, $4),
+                                      $3, $2, $4);
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist LYRICS_STRING
+       {
+               $$ = check_scheme_arg (parser, @4,
+                                      try_string_variants ($2, $4),
+                                      $3, $2, $4);
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist lyric_markup
        {
                $$ = check_scheme_arg (parser, @4, $4, $3, $2);
        }
        ;
 
+symbol_list_arg:
+       SYMBOL_LIST
+       | SYMBOL_LIST '.' symbol_list_rev
+       {
+               $$ = scm_append (scm_list_2 ($1, scm_reverse_x ($3, SCM_EOL)));
+       }
+       ;
+
+symbol_list_rev:
+       symbol_list_part
+       | symbol_list_rev '.' symbol_list_part
+       {
+               $$ = scm_append_x (scm_list_2 ($3, $1));
+       }
+       ;
+
+// symbol_list_part delivers elements in reverse copy.
+
+symbol_list_part:
+       symbol_list_element
+       {
+               SCM sym_l_p = ly_lily_module_constant ("symbol-list?");
+               $$ = try_string_variants (sym_l_p, $1);
+               if (SCM_UNBNDP ($$)) {
+                       parser->parser_error (@1, _("not a symbol"));
+                       $$ = SCM_EOL;
+               } else
+                       $$ = scm_reverse ($$);
+       }
+       ;
+
+
+symbol_list_element:
+       STRING
+       | LYRICS_STRING
+       | embedded_scm_bare
+       ;
+
+
 function_arglist_nonbackup:
        function_arglist_nonbackup_common
        | EXPECT_OPTIONAL EXPECT_SCM function_arglist embedded_scm_arg
        {
                $$ = check_scheme_arg (parser, @4, $4, $3, $2);
        }
-       | EXPECT_OPTIONAL EXPECT_SCM function_arglist SCM_IDENTIFIER
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed bare_number
        {
                $$ = check_scheme_arg (parser, @4, $4, $3, $2);
        }
-       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed bare_number
+       | function_arglist_nonbackup_reparse REPARSE SCM_ARG
        {
-               $$ = check_scheme_arg (parser, @4, $4, $3, $2);
+               $$ = check_scheme_arg (parser, @3, $3, $1, $2);
+       }
+       | function_arglist_nonbackup_reparse REPARSE lyric_element_music
+       {
+               $$ = check_scheme_arg (parser, @3, $3, $1, $2);
+       }
+       | function_arglist_nonbackup_reparse REPARSE symbol_list_arg
+       {
+               $$ = check_scheme_arg (parser, @3, $3, $1, $2);
+       }
+       ;
+
+function_arglist_nonbackup_reparse:
+       EXPECT_OPTIONAL EXPECT_SCM function_arglist SCM_IDENTIFIER
+       {
+               $$ = $3;
+               SCM res = try_string_variants ($2, $4);
+               if (!SCM_UNBNDP (res))
+                       if (scm_is_pair (res))
+                               MYREPARSE (@4, $2, SYMBOL_LIST, res);
+                       else
+                               MYREPARSE (@4, $2, SCM_ARG, res);
+               else if (scm_is_true
+                        (scm_call_1
+                         ($2, make_music_from_simple
+                          (parser, @4, $4))))
+                       MYREPARSE (@4, $2, LYRICS_STRING, $4);
+               else
+                       MYREPARSE (@4, $2, SCM_ARG, $4);
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist LYRICS_STRING
+       {
+               $$ = $3;
+               SCM res = try_string_variants ($2, $4);
+               if (!SCM_UNBNDP (res))
+                       if (scm_is_pair (res))
+                               MYREPARSE (@4, $2, SYMBOL_LIST, res);
+                       else
+                               MYREPARSE (@4, $2, SCM_ARG, res);
+               else if (scm_is_true
+                        (scm_call_1
+                         ($2, make_music_from_simple
+                          (parser, @4, $4))))
+                       MYREPARSE (@4, $2, LYRICS_STRING, $4);
+               else
+                       MYREPARSE (@4, $2, SCM_ARG, $4);
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist STRING
+       {
+               $$ = $3;
+               SCM res = try_string_variants ($2, $4);
+               if (!SCM_UNBNDP (res))
+                       if (scm_is_pair (res))
+                               MYREPARSE (@4, $2, SYMBOL_LIST, res);
+                       else
+                               MYREPARSE (@4, $2, SCM_ARG, res);
+               else
+                       MYREPARSE (@4, $2, SCM_ARG, $4);
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist lyric_markup
+       {
+               $$ = $3;
+               if (scm_is_true (scm_call_1 ($2, $4)))
+                       MYREPARSE (@4, $2, SCM_ARG, $4);
+               else if (scm_is_true
+                        (scm_call_1
+                         ($2, make_music_from_simple
+                          (parser, @4, $4))))
+                       MYREPARSE (@4, $2, LYRICS_STRING, $4);
+               else
+                       MYREPARSE (@4, $2, SCM_ARG, $4);
        }
        ;
 
@@ -1268,17 +1432,7 @@ function_arglist_backup:
                        $$ = scm_cons ($4, $3);
                } else {
                        $$ = scm_cons (loc_on_music (@3, $1), $3);
-                       MYBACKUP (SCM_IDENTIFIER, $4, @4);
-               }
-       }
-       EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep SCM_IDENTIFIER
-       {
-               if (scm_is_true (scm_call_1 ($2, $4)))
-               {
-                       $$ = scm_cons ($4, $3);
-               } else {
-                       $$ = scm_cons (loc_on_music (@3, $1), $3);
-                       MYBACKUP (SCM_IDENTIFIER, $4, @4);
+                       MYBACKUP (SCM_ARG, $4, @4);
                }
        }
        | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep post_event_nofinger
@@ -1291,21 +1445,13 @@ function_arglist_backup:
                        MYBACKUP (EVENT_IDENTIFIER, $4, @4);
                }
        }
-       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep lyric_element
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep lyric_markup
        {
-               // There is no point interpreting a lyrics string as
-               // an event, since we don't allow music possibly
-               // followed by durations or postevent into closed
-               // music, and we only accept closed music in optional
-               // arguments at the moment.  If this changes, more
-               // complex schemes might become interesting here as
-               // well: see how we do this at the mandatory argument
-               // point.
                if (scm_is_true (scm_call_1 ($2, $4)))
                        $$ = scm_cons ($4, $3);
                else {
                        $$ = scm_cons (loc_on_music (@3, $1), $3);
-                       MYBACKUP (LYRICS_STRING, $4, @4);
+                       MYBACKUP (LYRIC_ELEMENT, $4, @4);
                }
        }
        | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep UNSIGNED
@@ -1377,6 +1523,7 @@ function_arglist_backup:
                        MYREPARSE (@5, $2, REAL, n);
                        $$ = $3;
                } else {
+                       $$ = scm_cons (loc_on_music (@3, $1), $3);
                        MYBACKUP (REAL, n, @5);
                }
        }
@@ -1386,6 +1533,7 @@ function_arglist_backup:
                if (scm_is_true (scm_call_1 ($2, n))) {
                        $$ = scm_cons (n, $3);
                } else {
+                       $$ = scm_cons (loc_on_music (@3, $1), $3);
                        MYBACKUP (NUMBER_IDENTIFIER, n, @5);
                }
        }
@@ -1397,26 +1545,65 @@ function_arglist_backup:
        {
                $$ = scm_cons ($4, $3);
        }
-       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup BACKUP
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep SCM_IDENTIFIER
        {
-               $$ = scm_cons ($1, $3);
-               MYBACKUP(0, SCM_UNDEFINED, @3);
+               SCM res = try_string_variants ($2, $4);
+               if (!SCM_UNBNDP (res))
+                       if (scm_is_pair (res)) {
+                               $$ = $3;
+                               MYREPARSE (@4, $2, SYMBOL_LIST, res);
+                       }
+                       else
+                               $$ = scm_cons (res, $3);
+               else {
+                       $$ = scm_cons (loc_on_music (@3, $1), $3);
+                       MYBACKUP (SCM_IDENTIFIER, $4, @4);
+               }
        }
-       | function_arglist_backup REPARSE embedded_scm_arg_closed
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep STRING
        {
-               $$ = check_scheme_arg (parser, @3,
-                                      $3, $1, $2);
+               SCM res = try_string_variants ($2, $4);
+               if (!SCM_UNBNDP (res))
+                       if (scm_is_pair (res)) {
+                               $$ = $3;
+                               MYREPARSE (@4, $2, SYMBOL_LIST, res);
+                       }
+                       else
+                               $$ = scm_cons (res, $3);
+               else {
+                       $$ = scm_cons (loc_on_music (@3, $1), $3);
+                       MYBACKUP (STRING, $4, @4);
+               }
        }
-       | function_arglist_backup REPARSE SCM_IDENTIFIER
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep LYRICS_STRING
        {
-               $$ = check_scheme_arg (parser, @3,
-                                      $3, $1, $2);
+               SCM res = try_string_variants ($2, $4);
+               if (!SCM_UNBNDP (res))
+                       if (scm_is_pair (res)) {
+                               $$ = $3;
+                               MYREPARSE (@4, $2, SYMBOL_LIST, res);
+                       }
+                       else
+                               $$ = scm_cons (res, $3);
+               else {
+                       $$ = scm_cons (loc_on_music (@3, $1), $3);
+                       MYBACKUP (LYRICS_STRING, $4, @4);
+               }
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup BACKUP
+       {
+               $$ = scm_cons ($1, $3);
+               MYBACKUP(0, SCM_UNDEFINED, @3);
        }
        | function_arglist_backup REPARSE bare_number
        {
                $$ = check_scheme_arg (parser, @3,
                                       $3, $1, $2);
        }
+       | function_arglist_backup REPARSE symbol_list_arg
+       {
+               $$ = check_scheme_arg (parser, @3, $3, $1, $2);
+       }
        ;
 
 function_arglist:
@@ -1431,11 +1618,6 @@ function_arglist_common:
                $$ = check_scheme_arg (parser, @3,
                                       $3, $2, $1);
        }
-       | EXPECT_SCM function_arglist_optional SCM_IDENTIFIER
-       {
-               $$ = check_scheme_arg (parser, @3,
-                                      $3, $2, $1);
-       }
        | EXPECT_SCM function_arglist_closed_optional bare_number
        {
                $$ = check_scheme_arg (parser, @3,
@@ -1451,65 +1633,111 @@ function_arglist_common:
                $$ = check_scheme_arg (parser, @3,
                                       $3, $2, $1);
        }
-       | function_arglist_common_minus
-       | function_arglist_common_lyric
+       | EXPECT_SCM function_arglist_closed_optional '-' NUMBER_IDENTIFIER
+       {
+               SCM n = scm_difference ($4, SCM_UNDEFINED);
+               $$ = check_scheme_arg (parser, @4, n, $2, $1);
+       }
+       | function_arglist_common_reparse REPARSE SCM_ARG
+       {
+               $$ = check_scheme_arg (parser, @3,
+                                      $3, $1, $2);
+       }
+       | function_arglist_common_reparse REPARSE lyric_element_music
+       {
+               $$ = check_scheme_arg (parser, @3,
+                                      $3, $1, $2);
+       }
+       | function_arglist_common_reparse REPARSE bare_number
+       {
+               $$ = check_scheme_arg (parser, @3,
+                                      $3, $1, $2);
+       }
+       | function_arglist_common_reparse REPARSE symbol_list_arg
+       {
+               $$ = check_scheme_arg (parser, @3, $3, $1, $2);
+       }
        ;
 
-function_arglist_common_lyric:
-       EXPECT_SCM function_arglist_optional lyric_element
+function_arglist_common_reparse:
+       EXPECT_SCM function_arglist_optional SCM_IDENTIFIER
        {
-               // We check how the predicate thinks about a lyrics
-               // event or about a markup.  If it accepts neither, we
-               // backup the original token.  Otherwise we commit to
-               // taking the token.  Depending on what the predicate
-               // is willing to accept, we interpret as a string, as
-               // a lyric event, or ambiguously (meaning that if
-               // something looking like a duration or post event
-               // follows, we take the event, otherwise the string).
-               SCM lyric_event = MAKE_SYNTAX ("lyric-event", @3, $3,
-                                              parser->default_duration_.smobbed_copy ());
-               if (scm_is_true (scm_call_1 ($1, $3)))
-                       if (scm_is_true (scm_call_1 ($1, lyric_event)))
-                       {
-                               $$ = $2;
-                               MYREPARSE (@3, $1, LYRICS_STRING, $3);
-                       } else {
-                               $$ = scm_cons ($3, $2);
-                       }
-               else if (scm_is_true (scm_call_1 ($1, lyric_event)))
-               {
-                       $$ = $2;
+               $$ = $2;
+               SCM res = try_string_variants ($1, $3);
+               if (!SCM_UNBNDP (res))
+                       if (scm_is_pair (res))
+                               MYREPARSE (@3, $1, SYMBOL_LIST, res);
+                       else
+                               MYREPARSE (@3, $1, SCM_ARG, res);
+               else if (scm_is_true
+                        (scm_call_1
+                         ($1, make_music_from_simple (parser, @3, $3))))
                        MYREPARSE (@3, $1, LYRIC_ELEMENT, $3);
-               } else {
+               else
                        // This is going to flag a syntax error, we
                        // know the predicate to be false.
-                       check_scheme_arg (parser, @3,
-                                         $3, $2, $1);
-               }
+                       MYREPARSE (@3, $1, SCM_ARG, $3);
        }
-       | function_arglist_common_lyric REPARSE lyric_element_arg
+       | EXPECT_SCM function_arglist_optional STRING
        {
-               // This should never be false
-               $$ = check_scheme_arg (parser, @3,
-                                      $3, $1, $2);
+               $$ = $2;
+               SCM res = try_string_variants ($1, $3);
+               if (!SCM_UNBNDP (res))
+                       if (scm_is_pair (res))
+                               MYREPARSE (@3, $1, SYMBOL_LIST, res);
+                       else
+                               MYREPARSE (@3, $1, SCM_ARG, res);
+               else
+                       // This is going to flag a syntax error, we
+                       // know the predicate to be false.
+                       MYREPARSE (@3, $1, SCM_ARG, $3);
        }
-       ;
-
-function_arglist_common_minus:
-       EXPECT_SCM function_arglist_closed_optional '-' UNSIGNED
+       | EXPECT_SCM function_arglist_optional LYRICS_STRING
+       {
+               $$ = $2;
+               SCM res = try_string_variants ($1, $3);
+               if (!SCM_UNBNDP (res))
+                       if (scm_is_pair (res))
+                               MYREPARSE (@3, $1, SYMBOL_LIST, res);
+                       else
+                               MYREPARSE (@3, $1, SCM_ARG, res);
+               else if (scm_is_true
+                        (scm_call_1
+                         ($1, make_music_from_simple (parser, @3, $3))))
+                       MYREPARSE (@3, $1, LYRIC_ELEMENT, $3);
+               else
+                       // This is going to flag a syntax error, we
+                       // know the predicate to be false.
+                       MYREPARSE (@3, $1, SCM_ARG, $3);
+       }
+       | EXPECT_SCM function_arglist_optional lyric_markup
        {
+               $$ = $2;
+               if (scm_is_true (scm_call_1 ($1, $3)))
+                       MYREPARSE (@3, $1, SCM_ARG, $3);
+               else if (scm_is_true
+                        (scm_call_1
+                         ($1, make_music_from_simple (parser, @3, $3))))
+                       MYREPARSE (@3, $1, LYRIC_ELEMENT, $3);
+               else
+                       // This is going to flag a syntax error, we
+                       // know the predicate to be false.
+                       MYREPARSE (@3, $1, SCM_ARG, $3);
+       }
+       | EXPECT_SCM function_arglist_closed_optional '-' UNSIGNED
+       {
+               $$ = $2;
                SCM n = scm_difference ($4, SCM_UNDEFINED);
-               if (scm_is_true (scm_call_1 ($1, n))) {
-                       $$ = $2;
+               if (scm_is_true (scm_call_1 ($1, n)))
                        MYREPARSE (@4, $1, REAL, n);
-               else {
+               else {
                        Music *t = MY_MAKE_MUSIC ("FingeringEvent", @4);
                        t->set_property ("digit", $4);
-                       $$ = t->unprotect ();
-                       if (scm_is_true (scm_call_1 ($1, $$)))
-                               $$ = scm_cons ($$, $2);
+                       SCM m = t->unprotect ();
+                       if (scm_is_true (scm_call_1 ($1, m)))
+                               MYREPARSE (@4, $1, SCM_ARG, m);
                        else
-                               $$ = check_scheme_arg (parser, @3, n, $2, $1);
+                               MYREPARSE (@4, $1, SCM_ARG, $4);
                }
                
        }
@@ -1519,15 +1747,6 @@ function_arglist_common_minus:
                SCM n = scm_difference ($4, SCM_UNDEFINED);
                MYREPARSE (@4, $1, REAL, n);
        }
-       | EXPECT_SCM function_arglist_closed_optional '-' NUMBER_IDENTIFIER
-       {
-               SCM n = scm_difference ($4, SCM_UNDEFINED);
-               $$ = check_scheme_arg (parser, @4, n, $2, $1);
-       }
-       | function_arglist_common_minus REPARSE bare_number
-       {
-               $$ = check_scheme_arg (parser, @3, $3, $1, $2);
-       }
        ;
 
 function_arglist_closed:
@@ -1542,38 +1761,11 @@ function_arglist_closed_common:
                $$ = check_scheme_arg (parser, @3,
                                       $3, $2, $1);
        }
-       | EXPECT_SCM function_arglist_optional SCM_IDENTIFIER
-       {
-               $$ = check_scheme_arg (parser, @3,
-                                      $3, $2, $1);
-       }
        | EXPECT_SCM function_arglist_closed_optional bare_number
        {
                $$ = check_scheme_arg (parser, @3,
                                       $3, $2, $1);
        }
-       | EXPECT_SCM function_arglist_closed_optional '-' UNSIGNED
-       {
-               SCM n = scm_difference ($4, SCM_UNDEFINED);
-               if (scm_is_true (scm_call_1 ($1, n))) {
-                       $$ = scm_cons (n, $2);
-               } else {
-                       Music *t = MY_MAKE_MUSIC ("FingeringEvent", @4);
-                       t->set_property ("digit", $4);
-                       $$ = t->unprotect ();
-                       if (scm_is_true (scm_call_1 ($1, $$)))
-                               $$ = scm_cons ($$, $2);
-                       else
-                               $$ = check_scheme_arg (parser, @3, n, $2, $1);
-               }
-               
-       }
-       | EXPECT_SCM function_arglist_closed_optional '-' REAL
-       {
-               $$ = check_scheme_arg (parser, @3,
-                                      scm_difference ($4, SCM_UNDEFINED),
-                                      $2, $1);
-       }
        | EXPECT_SCM function_arglist_closed_optional '-' NUMBER_IDENTIFIER
        {
                $$ = check_scheme_arg (parser, @3,
@@ -1590,10 +1782,19 @@ function_arglist_closed_common:
                $$ = check_scheme_arg (parser, @3,
                                       $3, $2, $1);
        }
-       | EXPECT_SCM function_arglist_optional lyric_element
+       | function_arglist_common_reparse REPARSE SCM_ARG
        {
                $$ = check_scheme_arg (parser, @3,
-                                      $3, $2, $1);
+                                      $3, $1, $2);
+       }
+       | function_arglist_common_reparse REPARSE bare_number
+       {
+               $$ = check_scheme_arg (parser, @3,
+                                      $3, $1, $2);
+       }
+       | function_arglist_common_reparse REPARSE symbol_list_arg
+       {
+               $$ = check_scheme_arg (parser, @3, $3, $1, $2);
        }
        ;
 
@@ -1825,19 +2026,13 @@ context_change:
        ;
 
 
-property_path_revved:
-       embedded_scm_closed {
-               $$ = scm_cons ($1, SCM_EOL);
-       }
-       | property_path_revved embedded_scm_closed {
-               $$ = scm_cons ($2, $1);
-       }
-       ;
-
 property_path:
-       property_path_revved  {
+       symbol_list_rev  {
                $$ = scm_reverse_x ($1, SCM_EOL);
        }
+       | symbol_list_rev property_path {
+               $$ = scm_reverse_x ($1, $2);
+       }
        ;
 
 property_operation:
@@ -1849,15 +2044,73 @@ property_operation:
                $$ = scm_list_2 (ly_symbol2scm ("unset"),
                        scm_string_to_symbol ($2));
        }
-       | OVERRIDE simple_string property_path '=' scalar {
-               $$ = scm_append (scm_list_2 (scm_list_3 (ly_symbol2scm ("push"),
-                                                       scm_string_to_symbol ($2), $5),
-                                            $3));
+       | OVERRIDE property_path '=' scalar {
+               if (scm_ilength ($2) < 2) {
+                       parser->parser_error (@2, _("bad grob property path"));
+                       $$ = SCM_UNDEFINED;
+               } else {
+                       $$ = scm_cons (ly_symbol2scm ("push"),
+                                      scm_cons2 (scm_car ($2),
+                                                 $4,
+                                                 scm_cdr ($2)));
+               }
        }
-       | REVERT simple_string embedded_scm {
+       | REVERT revert_arg {
                $$ = scm_list_3 (ly_symbol2scm ("pop"),
-                       scm_string_to_symbol ($2), $3);
+                                scm_car ($2),
+                                scm_cdr ($2));
+       }
+       ;
+
+// This is all quite awkward for the sake of substantial backward
+// compatibility while at the same time allowing a more "natural" form
+// of specification not separating grob specification from grob
+// property path.  The purpose of this definition of revert_arg is to
+// allow the symbol list which specifies grob and property to revert
+// to be optionally be split into two parts after the grob (which in
+// this case is just the first element of the list).  symbol_list_part
+// is only one path component, but it can be parsed without lookahead,
+// so we can follow it with a synthetic BACKUP token when needed.  If
+// the first symbol_list_part already contains multiple elements (only
+// possible if a Scheme expression provides them), we just parse for
+// additional elements introduced by '.', which is what the
+// SYMBOL_LIST backup in connection with the immediately following
+// rule using symbol_list_arg does.
+//
+// As long as we don't have our coffers filled with both grob and at
+// least one grob property specification, the rest of the required
+// symbol list chain may be provided either with or without a leading
+// dot.  This is for both allowing the traditional
+// \revert Accidental #'color
+// as well as well as the "naive" form
+// \revert Accidental.color
+
+revert_arg:
+       revert_arg_part
+       {
+               if (scm_is_null ($1)
+                   || scm_is_null (scm_cdr ($1)))
+                       MYBACKUP (SCM_ARG, $1, @1);
+               else
+                       MYBACKUP (SYMBOL_LIST, scm_reverse_x ($1, SCM_EOL), @1);
+       }
+       | revert_arg BACKUP symbol_list_arg
+       {
+               $$ = $3;
+       }
+       ;
+
+// revert_arg_part delivers results in reverse
+revert_arg_part:
+       symbol_list_part
+       | revert_arg BACKUP SCM_ARG '.' symbol_list_part
+       {
+               $$ = scm_append_x (scm_list_2 ($5, $3));
        }
+       | revert_arg BACKUP SCM_ARG symbol_list_part
+       {
+               $$ = scm_append_x (scm_list_2 ($4, $3));
+       }               
        ;
 
 context_def_mod:
@@ -1895,52 +2148,141 @@ context_mod:
        }
        ;
 
-context_prop_spec:
-       simple_string {
-               if (!is_regular_identifier ($1))
+// If defined, at least two members.
+grob_prop_spec:
+       symbol_list_rev
+       {
+               SCM l = scm_reverse_x ($1, SCM_EOL);
+               if (scm_is_pair (l)
+                   && to_boolean
+                   (scm_object_property (scm_car (l),
+                                         ly_symbol2scm ("is-grob?"))))
+                       l = scm_cons (ly_symbol2scm ("Bottom"), l);
+               if (scm_is_null (l) || scm_is_null (scm_cdr (l))) {
+                       parser->parser_error (@1, _ ("bad grob property path"));
+                       l = SCM_UNDEFINED;
+               }
+               $$ = l;
+       }
+       ;
+
+// If defined, at least three members
+grob_prop_path:
+       grob_prop_spec
+       {
+               if (!SCM_UNBNDP ($1) && scm_is_null (scm_cddr ($1)))
                {
-                       @$.error (_("Grob name should be alphanumeric"));
+                       parser->parser_error (@1, _ ("bad grob property path"));
+                       $$ = SCM_UNDEFINED;
+               }
+       }
+       | grob_prop_spec property_path
+       {
+               if (!SCM_UNBNDP ($1)) {
+                       $$ = scm_append_x (scm_list_2 ($1, $2));
+                       if (scm_is_null (scm_cddr ($$))) {
+                               parser->parser_error (@$, _ ("bad grob property path"));
+                               $$ = SCM_UNDEFINED;
+                       }
                }
 
-               $$ = scm_list_2 (ly_symbol2scm ("Bottom"),
-                       scm_string_to_symbol ($1));
        }
-       | simple_string '.' simple_string {
-               $$ = scm_list_2 (scm_string_to_symbol ($1),
-                       scm_string_to_symbol ($3));
+       ;
+
+// Exactly two elements or undefined
+context_prop_spec:
+       symbol_list_rev
+       {
+               SCM l = scm_reverse_x ($1, SCM_EOL);
+               switch (scm_ilength (l)) {
+               case 1:
+                       l = scm_cons (ly_symbol2scm ("Bottom"), l);
+               case 2:
+                       break;
+               default:
+                       parser->parser_error (@1, _ ("bad context property path"));
+                       l = SCM_UNDEFINED;
+               }
+               $$ = l;
        }
        ;
 
 simple_music_property_def:
-       OVERRIDE context_prop_spec property_path '=' scalar {
-               $$ = scm_append (scm_list_2 (scm_list_n (scm_car ($2),
-                               ly_symbol2scm ("OverrideProperty"),
-                               scm_cadr ($2),
-                               $5, SCM_UNDEFINED),
-                               $3));
-       }
-       | REVERT context_prop_spec embedded_scm {
-               $$ = scm_list_4 (scm_car ($2),
-                       ly_symbol2scm ("RevertProperty"),
-                       scm_cadr ($2),
-                       $3);
+       OVERRIDE grob_prop_path '=' scalar {
+               if (SCM_UNBNDP ($2))
+                       $$ = SCM_UNDEFINED;
+               else {
+                       $$ = scm_list_5 (scm_car ($2),
+                                        ly_symbol2scm ("OverrideProperty"),
+                                        scm_cadr ($2),
+                                        $4,
+                                        scm_cddr ($2));
+               }
+       }
+       | REVERT simple_revert_context revert_arg {
+               $$ = scm_list_4 ($2,
+                                ly_symbol2scm ("RevertProperty"),
+                                scm_car ($3),
+                                scm_cdr ($3));
        }
        | SET context_prop_spec '=' scalar {
-               $$ = scm_list_4 (scm_car ($2),
-                       ly_symbol2scm ("PropertySet"),
-                       scm_cadr ($2),
-                       $4);
+               if (SCM_UNBNDP ($2))
+                       $$ = SCM_UNDEFINED;
+               else
+                       $$ = scm_list_4 (scm_car ($2),
+                                        ly_symbol2scm ("PropertySet"),
+                                        scm_cadr ($2),
+                                        $4);
        }
        | UNSET context_prop_spec {
-               $$ = scm_list_3 (scm_car ($2),
-                       ly_symbol2scm ("PropertyUnset"),
-                       scm_cadr ($2));
+               if (SCM_UNBNDP ($2))
+                       $$ = SCM_UNDEFINED;
+               else
+                       $$ = scm_list_3 (scm_car ($2),
+                                        ly_symbol2scm ("PropertyUnset"),
+                                        scm_cadr ($2));
+       }
+       ;
+
+
+// This is all quite awkward for the sake of substantial backward
+// compatibility while at the same time allowing a more "natural" form
+// of specification not separating grob specification from grob
+// property path.  The purpose of this definition of
+// simple_revert_context is to allow the symbol list which specifies
+// grob and property to revert to be optionally be split into two
+// parts after the grob (which may be preceded by a context
+// specification, a case which we distinguish by checking whether the
+// first symbol is a valid grob symbol instead).
+//
+// See revert_arg above for the main work horse of this arrangement.
+// simple_revert_context just caters for the context and delegates the
+// rest of the job to revert_arg.
+
+simple_revert_context:
+       symbol_list_part
+       {
+               $1 = scm_reverse_x ($1, SCM_EOL);
+               if (scm_is_null ($1)
+                   || to_boolean
+                   (scm_object_property (scm_car ($1),
+                                         ly_symbol2scm ("is-grob?")))) {
+                       $$ = ly_symbol2scm ("Bottom");
+                       parser->lexer_->push_extra_token (SCM_IDENTIFIER, $1);
+               } else {
+                       $$ = scm_car ($1);
+                       parser->lexer_->push_extra_token (SCM_IDENTIFIER,
+                                                         scm_cdr ($1));
+               }
        }
        ;
 
 music_property_def:
        simple_music_property_def {
-               $$ = LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant ("property-operation"), scm_cons2 (parser->self_scm (), make_input (@$), $1));
+               if (SCM_UNBNDP ($1))
+                       $$ = MAKE_SYNTAX ("void-music", @1);
+               else
+                       $$ = LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant ("property-operation"), scm_cons2 (parser->self_scm (), make_input (@$), $1));
        }
        ;
 
@@ -1985,6 +2327,7 @@ scalar:
        | bare_number
        | FRACTION
        | lyric_element
+       | STRING
        ;
 
 scalar_closed:
@@ -1993,6 +2336,7 @@ scalar_closed:
        | bare_number
        | FRACTION
        | lyric_element
+       | STRING
        ;
 
 
@@ -2421,7 +2765,7 @@ gen_text_def:
                        make_simple_markup ($1));
                $$ = t->unprotect ();
        }
-       | embedded_scm_bare
+       | embedded_scm_closed
        {
                Music *m = unsmob_music ($1);
                if (m && m->is_mus_type ("post-event"))
@@ -2758,31 +3102,9 @@ lyric_element:
        | LYRICS_STRING {
                $$ = $1;
        }
+       | LYRIC_ELEMENT
        ;
 
-lyric_element_arg:
-       lyric_element
-       | lyric_element multiplied_duration post_events {
-               $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
-               if (scm_is_pair ($3))
-                       unsmob_music ($$)->set_property
-                               ("articulations", scm_reverse_x ($3, SCM_EOL));
-       }
-       | lyric_element post_event post_events {
-               $$ = MAKE_SYNTAX ("lyric-event", @$, $1,
-                                 parser->default_duration_.smobbed_copy ());
-               unsmob_music ($$)->set_property
-                       ("articulations", scm_cons ($2, scm_reverse_x ($3, SCM_EOL)));
-       }
-       | LYRIC_ELEMENT optional_notemode_duration post_events {
-               $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
-               if (scm_is_pair ($3))
-                       unsmob_music ($$)->set_property
-                               ("articulations", scm_reverse_x ($3, SCM_EOL));
-       }
-       ;
-
-
 lyric_element_music:
        lyric_element optional_notemode_duration post_events {
                $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
@@ -3161,12 +3483,6 @@ Lily_lexer::try_special_identifiers (SCM *destination, SCM sid)
                 *destination = unsmob_context_mod (sid)->smobbed_copy ();
 
                 return CONTEXT_MOD_IDENTIFIER;
-       } else if (unsmob_score (sid)) {
-               Score *score = new Score (*unsmob_score (sid));
-               *destination = score->self_scm ();
-
-               score->unprotect ();
-               return SCORE_IDENTIFIER;
        } else if (Music *mus = unsmob_music (sid)) {
                mus = mus->clone ();
                *destination = mus->self_scm ();
@@ -3210,14 +3526,34 @@ get_next_unique_lyrics_context_id ()
        return scm_from_locale_string (s);
 }
 
+// check_scheme_arg checks one argument with a given predicate for use
+// in an argument list and throws a syntax error if it is unusable.
+// The argument is prepended to the argument list in any case.  After
+// throwing a syntax error, the argument list is terminated with #f as
+// its last cdr in order to mark it as uncallable while not losing
+// track of its total length.
+//
+// There are a few special considerations: if optional argument disp
+// is given (otherwise it defaults to SCM_UNDEFINED), it will be used
+// instead of arg in a prospective error message.  This is useful if
+// arg is not the actual argument but rather a transformation of it.
+//
+// If arg itself is SCM_UNDEFINED, the predicate is considered false
+// and an error message using disp is produced unconditionally.
+
 SCM check_scheme_arg (Lily_parser *parser, Input loc,
-                     SCM arg, SCM args, SCM pred)
+                     SCM arg, SCM args, SCM pred, SCM disp)
 {
-       args = scm_cons (arg, args);
-       if (scm_is_true (scm_call_1 (pred, arg)))
-               return args;
+       if (SCM_UNBNDP (arg))
+               args = scm_cons (disp, args);
+       else {
+               args = scm_cons (arg, args);
+               if (scm_is_true (scm_call_1 (pred, arg)))
+                       return args;
+       }
        scm_set_cdr_x (scm_last_pair (args), SCM_EOL);
-       MAKE_SYNTAX ("argument-error", loc, scm_length (args), pred, arg);
+       MAKE_SYNTAX ("argument-error", loc, scm_length (args), pred,
+                    SCM_UNBNDP (disp) ? arg : disp);
        scm_set_cdr_x (scm_last_pair (args), SCM_BOOL_F);
        return args;
 }
@@ -3233,9 +3569,54 @@ SCM loc_on_music (Input loc, SCM arg)
        return arg;
 }
 
+SCM
+try_string_variants (SCM pred, SCM str)
+{
+       // a matching predicate is always ok
+       if (scm_is_true (scm_call_1 (pred, str)))
+               return str;
+       // a symbol may be interpreted as a list of symbols if it helps
+       if (scm_is_symbol (str)) {
+               str = scm_list_1 (str);
+               if (scm_is_true (scm_call_1 (pred, str)))
+                       return str;
+               return SCM_UNDEFINED;
+       }
+
+       // If this cannot be a string representation of a symbol list,
+       // we are through.
+
+       if (!is_regular_identifier (str, true))
+               return SCM_UNDEFINED;
+
+       str = scm_string_split (str, SCM_MAKE_CHAR ('.'));
+       for (SCM p = str; scm_is_pair (p); p = scm_cdr (p))
+               scm_set_car_x (p, scm_string_to_symbol (scm_car (p)));
+
+       // Let's attempt the symbol list interpretation first.
+
+       if (scm_is_true (scm_call_1 (pred, str)))
+               return str;
+
+       // If there is just one symbol in the list, we might interpret
+       // it as a single symbol
+
+       if (scm_is_null (scm_cdr (str)))
+       {
+               str = scm_car (str);
+               if (scm_is_true (scm_call_1 (pred, str)))
+                       return str;
+       }
+
+       return SCM_UNDEFINED;
+}
+
 bool
-is_regular_identifier (SCM id)
+is_regular_identifier (SCM id, bool multiple)
 {
+  if (!scm_is_string (id))
+         return false;
+
   string str = ly_scm2string (id);
 
   bool middle = false;
@@ -3247,7 +3628,7 @@ is_regular_identifier (SCM id)
              || (c >= 'A' && c <= 'Z')
              || c > 0x7f)
                  middle = true;
-         else if (middle && (c == '-' || c == '_'))
+         else if (middle && (c == '-' || c == '_' || (multiple && c == '.')))
                  middle = false;
          else
                  return false;
@@ -3261,17 +3642,19 @@ make_music_from_simple (Lily_parser *parser, Input loc, SCM simple)
        if (unsmob_music (simple))
                return simple;
        if (parser->lexer_->is_note_state ()) {
-               Music *n = MY_MAKE_MUSIC ("NoteEvent", loc);
-               n->set_property ("duration", parser->default_duration_.smobbed_copy ());
-               if (scm_is_symbol (simple))
+               if (scm_is_symbol (simple)) {
+                       Music *n = MY_MAKE_MUSIC ("NoteEvent", loc);
+                       n->set_property ("duration", parser->default_duration_.smobbed_copy ());
                        n->set_property ("drum-type", simple);
-               else if (unsmob_pitch (simple))
+                       return n->unprotect ();
+               }
+               if (unsmob_pitch (simple)) {
+                       Music *n = MY_MAKE_MUSIC ("NoteEvent", loc);
+                       n->set_property ("duration", parser->default_duration_.smobbed_copy ());
                        n->set_property ("pitch", simple);
-               else {
-                       n->unprotect ();
-                       return simple;
+                       return n->unprotect ();
                }
-               return n->unprotect ();
+               return simple;
        } else if (parser->lexer_->is_lyric_state ()) {
                if (Text_interface::is_markup (simple))
                        return MAKE_SYNTAX ("lyric-event", loc, simple,