]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/parser.yy
* lily/lexer.ll, lily/parser.yy: Add EXPECT_NO_MORE_ARGS token, to
[lilypond.git] / lily / parser.yy
index 1d54ba97601290bdb5da524b8be090286f9080f0..6299ad3eb9e7b0d8b42e175d28edb9e0754ded87 100644 (file)
@@ -9,6 +9,7 @@
 
 %{
 
+#define YYDEBUG 1
 #define YYERROR_VERBOSE 1
 #define YYPARSE_PARAM my_lily_parser
 #define YYLEX_PARAM my_lily_parser
@@ -74,7 +75,6 @@ using namespace std;
 #include "context-def.hh"
 #include "dimensions.hh"
 #include "file-path.hh"
-#include "input-smob.hh"
 #include "input.hh"
 #include "international.hh"
 #include "lily-guile.hh"
@@ -250,13 +250,19 @@ If we give names, Bison complains.
 %token CHORDMODIFIERS
 %token LYRIC_MARKUP
 %token MULTI_MEASURE_REST
-%token SCM_T
 
 
 %token <i> DIGIT
 %token <i> E_UNSIGNED
 %token <i> UNSIGNED
 
+/* Artificial tokens, for more generic function syntax */
+%token <i> EXPECT_MARKUP;
+%token <i> EXPECT_MUSIC;
+%token <i> EXPECT_SCM;
+/* After the last argument. */
+%token <i> EXPECT_NO_MORE_ARGS;
+
 %token <scm> BOOK_IDENTIFIER
 %token <scm> CHORDMODIFIER_PITCH
 %token <scm> CHORD_MODIFIER
@@ -278,22 +284,6 @@ If we give names, Bison complains.
 %token <scm> MARKUP_HEAD_SCM0_SCM1_SCM2
 %token <scm> MARKUP_IDENTIFIER
 %token <scm> MUSIC_FUNCTION
-%token <scm> MUSIC_FUNCTION_MARKUP 
-%token <scm> MUSIC_FUNCTION_MARKUP_MARKUP 
-%token <scm> MUSIC_FUNCTION_MARKUP_MARKUP_MUSIC 
-%token <scm> MUSIC_FUNCTION_MARKUP_MUSIC 
-%token <scm> MUSIC_FUNCTION_MARKUP_MUSIC_MUSIC 
-%token <scm> MUSIC_FUNCTION_MUSIC 
-%token <scm> MUSIC_FUNCTION_MUSIC_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM 
-%token <scm> MUSIC_FUNCTION_SCM_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM_MUSIC_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM_SCM_MUSIC_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM_SCM 
-%token <scm> MUSIC_FUNCTION_SCM_SCM_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM_SCM_SCM 
-%token <scm> MUSIC_FUNCTION_SCM_SCM_SCM_MUSIC 
-%token <scm> MUSIC_FUNCTION_SCM_SCM_SCM_SCM_MUSIC 
 %token <scm> MUSIC_IDENTIFIER
 %token <scm> NOTENAME_PITCH
 %token <scm> NUMBER_IDENTIFIER
@@ -301,7 +291,7 @@ If we give names, Bison complains.
 %token <scm> REAL
 %token <scm> RESTNAME
 %token <scm> SCM_IDENTIFIER
-%token <scm> SCM_T
+%token <scm> SCM_TOKEN
 %token <scm> SCORE_IDENTIFIER
 %token <scm> STRING
 %token <scm> STRING_IDENTIFIER
@@ -362,10 +352,6 @@ If we give names, Bison complains.
 %type <scm> absolute_pitch
 %type <scm> assignment_id
 %type <scm> bare_number
-%type <scm> music_function_event
-%type <scm> music_function_chord_body
-%type <scm> music_function_musicless_prefix
-%type <scm> music_function_musicless_function
 %type <scm> bass_figure
 %type <scm> figured_bass_modification
 %type <scm> br_bass_figure
@@ -387,6 +373,11 @@ If we give names, Bison complains.
 %type <scm> figure_spec
 %type <scm> fraction
 %type <scm> full_markup
+%type <scm> function_scm_argument
+%type <scm> function_arglist
+%type <scm> function_arglist_music_last
+%type <scm> function_arglist_nonmusic_last
+%type <scm> function_arglist_nonmusic
 %type <scm> identifier_init
 %type <scm> lilypond_header
 %type <scm> lilypond_header_body
@@ -403,6 +394,9 @@ If we give names, Bison complains.
 %type <scm> mode_changing_head
 %type <scm> mode_changing_head_with_context
 %type <scm> multiplied_duration
+%type <scm> music_function_identifier_musicless_prefix
+%type <scm> music_function_event
+%type <scm> music_function_chord_body
 %type <scm> new_chord
 %type <scm> new_lyrics
 %type <scm> number_expression
@@ -428,7 +422,6 @@ If we give names, Bison complains.
 %type <scm> step_number
 %type <scm> step_numbers 
 %type <scm> string
-%type <scm> function_scm_argument
 
 %type <score> score_block
 %type <score> score_body
@@ -504,7 +497,7 @@ toplevel_expression:
        ;
 
 embedded_scm:
-       SCM_T
+       SCM_TOKEN
        | SCM_IDENTIFIER
        ;
 
@@ -535,15 +528,6 @@ assignment_id:
 
 assignment:
        assignment_id '=' identifier_init  {
-               if (! is_regular_identifier ($1))
-               {
-#if 0
-                       /* no longer valid with dashes in \paper{} block. */ 
-                       @1.warning (_ ("identifier should have alphabetic characters only"));
-#endif
-               }
-
-
                PARSER->lexer_->set_identifier ($1, $3);
 
 /*
@@ -616,11 +600,11 @@ context_def_spec_block:
 context_def_spec_body:
        /**/ {
                $$ = Context_def::make_scm ();
-               unsmob_context_def ($$)->set_spot (@$);
+               unsmob_context_def ($$)->origin ()->set_spot (@$);
        }
        | CONTEXT_DEF_IDENTIFIER {
                $$ = $1;
-               unsmob_context_def ($$)->set_spot (@$);
+               unsmob_context_def ($$)->origin ()->set_spot (@$);
        }
        | context_def_spec_body GROBDESCRIPTIONS embedded_scm {
                Context_def*td = unsmob_context_def ($$);
@@ -652,14 +636,15 @@ book_block:
 book_body:
        {
                $$ = new Book;
-               $$->set_spot (@$);
+               $$->origin ()->set_spot (@$);
                $$->paper_ = dynamic_cast<Output_def*> (unsmob_output_def (PARSER->lexer_->lookup_identifier ("$defaultpaper"))->clone ());
                $$->paper_->unprotect ();
                $$->header_ = PARSER->lexer_->lookup_identifier ("$defaultheader"); 
        }
        | BOOK_IDENTIFIER {
                $$ = unsmob_book ($1);
-               $$->set_spot (@$);
+               $$->protect ();
+               $$->origin ()->set_spot (@$);
        }
        | book_body paper_block {
                $$->paper_ = $2;
@@ -700,11 +685,12 @@ score_body:
                // pass ownernship to C++ again.
                $$ = unsmob_score (score);
                $$->protect ();
-               $$->set_spot (@$);
+               $$->origin ()->set_spot (@$);
        }
        | SCORE_IDENTIFIER {
                $$ = unsmob_score ($1);
-               $$->set_spot (@$);
+               $$->protect ();
+               $$->origin ()->set_spot (@$);
        }
        | score_body object_id_setting {
                $$->user_key_ = ly_scm2string ($2);
@@ -740,6 +726,7 @@ paper_block:
                if ($$->lookup_variable (ly_symbol2scm ("is-paper")) != SCM_BOOL_T)
                {
                        PARSER->parser_error (@1, _ ("need \\paper for paper block"));
+                       $1->unprotect ();
                        $$ = get_paper (PARSER);
                }
        }
@@ -788,9 +775,11 @@ output_def_body:
        }
        | output_def_head_with_mode_switch '{' OUTPUT_DEF_IDENTIFIER    {
                $1->unprotect ();
+
                Output_def *o = unsmob_output_def ($3);
                o->input_origin_.set_spot (@$);
                $$ = o;
+               $$->protect ();
                PARSER->lexer_->remove_scope ();
                PARSER->lexer_->add_scope (o->scope_);
        }
@@ -800,15 +789,6 @@ output_def_body:
        | output_def_body context_def_spec_block        {
                assign_context_def ($$, $2);
        }
-       | output_def_body tempo_event  {
-               /*
-                       junk this ? there already is tempo stuff in
-                       music.
-               */
-               int m = scm_to_int (unsmob_music($2)->get_property ("metronome-count"));
-               Duration *d = unsmob_duration (unsmob_music($2)->get_property ("tempo-unit"));
-               set_tempo ($$, d->get_length (), m);
-       }
        | output_def_body error {
 
        }
@@ -816,11 +796,8 @@ output_def_body:
 
 tempo_event:
        TEMPO steno_duration '=' bare_unsigned  {
-               Music *m = MY_MAKE_MUSIC ("MetronomeChangeEvent");
-               m->set_property ("tempo-unit", $2);
-               m->set_property ("metronome-count", scm_from_int ( $4));
-               $$ = m->unprotect ();
-       }
+               $$ = MAKE_SYNTAX ("tempo", @$, $2, scm_int2num ($4));
+       }                               
        ;
 
 /*
@@ -942,72 +919,48 @@ function_scm_argument:
        | simple_string
        ;
 
-/*
-TODO: use code generation for this
-*/
-music_function_musicless_function:
-       MUSIC_FUNCTION {
-               $$ = scm_list_2 ($1, make_input (@$));
-       }
-       | MUSIC_FUNCTION_SCM function_scm_argument {
-               $$ = scm_list_3 ($1, make_input (@$), $2);
-       }
-       | MUSIC_FUNCTION_MARKUP full_markup {
-               $$ = scm_list_3 ($1, make_input (@$), $2);
-       }
-       | MUSIC_FUNCTION_SCM_SCM function_scm_argument function_scm_argument {
-               $$ = scm_list_4 ($1, make_input (@$), $2, $3);
-       }
-       | MUSIC_FUNCTION_SCM_SCM_SCM function_scm_argument function_scm_argument function_scm_argument {
-               $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4);
-       }
-       | MUSIC_FUNCTION_MARKUP_MARKUP full_markup full_markup {
-               $$ = scm_list_4 ($1, make_input (@$), $2, $3);
+/* An argument list. If a function \foo expects scm scm music, then the lexer expands \foo into the token sequence:
+ MUSIC_FUNCTION EXPECT_MUSIC EXPECT_SCM EXPECT_SCM
+and this rule returns the reversed list of arguments. */
+
+function_arglist_music_last:
+       EXPECT_MUSIC function_arglist music {
+               $$ = scm_cons ($3, $2);
        }
        ;
 
-/*
-TODO: use code generation for this
-*/
-music_function_musicless_prefix:
-       MUSIC_FUNCTION_MUSIC {
-               $$ = scm_list_2 ($1, make_input (@$));
+function_arglist_nonmusic_last:
+       EXPECT_MARKUP function_arglist full_markup {
+               $$ = scm_cons ($3, $2);
        }
-       | MUSIC_FUNCTION_SCM_MUSIC function_scm_argument { 
-               $$ = scm_list_3 ($1, make_input (@$), $2);
+       | EXPECT_SCM function_arglist function_scm_argument {
+               $$ = scm_cons ($3, $2);
        }
-       | MUSIC_FUNCTION_SCM_SCM_MUSIC function_scm_argument function_scm_argument {
-               $$ = scm_list_4 ($1, make_input (@$), $2, $3);
+       ;
+
+function_arglist_nonmusic: EXPECT_NO_MORE_ARGS {
+               $$ = SCM_EOL;
        }
-       | MUSIC_FUNCTION_SCM_SCM_SCM_MUSIC function_scm_argument function_scm_argument function_scm_argument {
-               $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4);
+       | EXPECT_MARKUP function_arglist_nonmusic full_markup {
+               $$ = scm_cons ($3, $2);
        }
-       | MUSIC_FUNCTION_SCM_SCM_SCM_SCM_MUSIC function_scm_argument function_scm_argument function_scm_argument function_scm_argument {
-               $$ = scm_list_n ($1, make_input (@$), $2, $3, $4, $5, SCM_UNDEFINED);
+       | EXPECT_SCM function_arglist_nonmusic function_scm_argument {
+               $$ = scm_cons ($3, $2);
        }
-       | MUSIC_FUNCTION_MARKUP_MUSIC full_markup {
-               $$ = scm_list_3 ($1, make_input (@$), $2);
+       ;
+
+function_arglist: EXPECT_NO_MORE_ARGS {
+               /* This is for 0-ary functions, so they don't need to
+                  read a lookahead token */
+               $$ = SCM_EOL;
        }
+       | function_arglist_music_last
+       | function_arglist_nonmusic_last
        ;
 
 generic_prefix_music_scm:
-       music_function_musicless_function {
-               $$ = $1;
-       }
-       | music_function_musicless_prefix music {
-               $$ = ly_append2 ($1, scm_list_1 ($2));
-       }
-       | MUSIC_FUNCTION_MUSIC_MUSIC music music {
-               $$ = scm_list_4 ($1, make_input (@$), $2, $3);
-       }
-       | MUSIC_FUNCTION_SCM_MUSIC_MUSIC function_scm_argument music music {
-               $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4);
-       }
-       | MUSIC_FUNCTION_SCM_SCM_MUSIC_MUSIC function_scm_argument function_scm_argument music music {
-               $$ = scm_list_n ($1, make_input (@$), $2, $3, $4, $5, SCM_UNDEFINED);
-       }
-       | MUSIC_FUNCTION_MARKUP_MUSIC_MUSIC full_markup music music {
-               $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4);
+       MUSIC_FUNCTION function_arglist {
+               $$ = ly_append2 (scm_list_2 ($1, make_input (@$)), scm_reverse_x ($2, SCM_EOL));
        }
        ;
 
@@ -1414,24 +1367,38 @@ chord_body_element:
        }
        ;
 
+music_function_identifier_musicless_prefix: MUSIC_FUNCTION {
+               SCM sig = scm_object_property (yylval.scm, ly_symbol2scm ("music-function-signature"));
+               if (scm_is_pair (sig) && to_boolean (scm_memq (ly_music_p_proc, scm_cdr (scm_reverse (sig)))))
+               {
+                       PARSER->parser_error (@$, "Music function applied to event may not have a Music argument, except as the last argument.");
+               }
+       }
+       ;
+
 music_function_chord_body:
-       music_function_musicless_function {
-               $$ = $1;
+       /* We could allow chord functions to have multiple music arguments,
+          but it's more consistent with music_function_event if we
+          prohibit it here too */
+       music_function_identifier_musicless_prefix EXPECT_MUSIC function_arglist_nonmusic chord_body_element {
+               $$ = ly_append2 (scm_list_2 ($1, make_input (@$)), scm_reverse_x ($3, scm_list_1 ($4)));
        }
-       | music_function_musicless_prefix chord_body_element {
-               $$ = ly_append2 ($1, scm_list_1 ($2));
+       | music_function_identifier_musicless_prefix function_arglist_nonmusic {
+               $$ = ly_append2 (scm_list_2 ($1, make_input (@$)), scm_reverse_x ($2, SCM_EOL));
        }
        ;
 
 music_function_event:
-       music_function_musicless_prefix post_event {
-               $$ = ly_append2 ($1, scm_list_1 ($2));
+       /* Post-events can only have the last argument as music, without this
+          restriction we get a shift/reduce conflict from e.g.
+          c8-\partcombine c8 -. */
+       music_function_identifier_musicless_prefix EXPECT_MUSIC function_arglist_nonmusic post_event {
+               $$ = ly_append2 (scm_list_2 ($1, make_input (@$)), scm_reverse_x ($3, scm_list_1 ($4)));
        }
-       | music_function_musicless_function {
-               $$ = $1;
+       | music_function_identifier_musicless_prefix function_arglist_nonmusic {
+               $$ = ly_append2 (scm_list_2 ($1, make_input (@$)), scm_reverse_x ($2, SCM_EOL));
        }
        ;
-       
 
 command_element:
        command_event {
@@ -2342,11 +2309,9 @@ markup:
 %%
 
 void
-Lily_parser::set_yydebug (bool )
+Lily_parser::set_yydebug (bool x)
 {
-#if 0
-       yydebug = 1;
-#endif
+       yydebug = x;
 }
 
 void
@@ -2372,17 +2337,26 @@ Lily_lexer::try_special_identifiers (SCM *destination, SCM sid)
                *destination = sid;
                return STRING_IDENTIFIER;
        } else if (unsmob_book (sid)) {
-               *destination = unsmob_book (sid)->clone ()->self_scm ();
+               Book *book =  unsmob_book (sid)->clone ();
+               *destination = book->self_scm ();
+               book->unprotect ();
+
                return BOOK_IDENTIFIER;
        } else if (scm_is_number (sid)) {
                *destination = sid;
                return NUMBER_IDENTIFIER;
        } else if (unsmob_context_def (sid)) {
-               *destination = unsmob_context_def (sid)->clone_scm ();
+               Context_def *def= unsmob_context_def (sid)->clone ();
+
+               *destination = def->self_scm ();
+               def->unprotect ();
+               
                return CONTEXT_DEF_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 ();
@@ -2393,6 +2367,7 @@ Lily_lexer::try_special_identifiers (SCM *destination, SCM sid)
                bool is_event = scm_memq (ly_symbol2scm ("event"), mus->get_property ("types"))
                        != SCM_BOOL_F;
 
+               mus->unprotect ();
                return is_event ? EVENT_IDENTIFIER : MUSIC_IDENTIFIER;
        } else if (unsmob_duration (sid)) {
                *destination = unsmob_duration (sid)->smobbed_copy ();
@@ -2400,8 +2375,9 @@ Lily_lexer::try_special_identifiers (SCM *destination, SCM sid)
        } else if (unsmob_output_def (sid)) {
                Output_def *p = unsmob_output_def (sid);
                p = p->clone ();
-
+       
                *destination = p->self_scm ();
+               p->unprotect ();
                return OUTPUT_DEF_IDENTIFIER;
        } else if (Text_interface::is_markup (sid)) {
                *destination = sid;
@@ -2499,7 +2475,7 @@ void
 set_music_properties (Music *p, SCM a)
 {
   for (SCM k = a; scm_is_pair (k); k = scm_cdr (k))
-       p->internal_set_property (scm_caar (k), scm_cdar (k));
+       p->set_property (scm_caar (k), scm_cdar (k));
 }