From: Erik Sandberg Date: Fri, 22 Sep 2006 06:18:00 +0000 (+0000) Subject: 2006-09-22 Erik Sandberg X-Git-Tag: cvs/HEAD~70 X-Git-Url: https://git.donarmstrong.com/lilypond.git?a=commitdiff_plain;h=2c7c33881c88968238c05d989c19bd5fa25ec316;p=lilypond.git 2006-09-22 Erik Sandberg * lily/lexer.ll: remove limitation on music function arity. New mode extratoken, which inserts extra EXPECT_* tokens after MUSIC_FUNCTION token. Junk all MUSIC_FUNCTION_* tokens. * lily/parser.yy: Change grammar for music function accordingly. * lily/include/lily-parser.hh: New method get_state, new member hidden_state. Works around a problem when parser fetches MUSIC_FUNCTION token but not the following EXPECT_* token. --- diff --git a/ChangeLog b/ChangeLog index 894e7e8dbc..999a91a5ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2006-09-22 Erik Sandberg + + * lily/lexer.ll: remove limitation on music function arity. New + mode extratoken, which inserts extra EXPECT_* tokens after + MUSIC_FUNCTION token. Junk all MUSIC_FUNCTION_* tokens. + + * lily/parser.yy: Change grammar for music function accordingly. + + * lily/include/lily-parser.hh: New method get_state, new member + hidden_state. Works around a problem when parser fetches + MUSIC_FUNCTION token but not the following EXPECT_* token. + 2006-09-21 Graham Percival * Documentation/user/tweaks.itely (Fitting music onto fewer diff --git a/lily/include/lily-lexer.hh b/lily/include/lily-lexer.hh index d0a188ab69..b22038fbeb 100644 --- a/lily/include/lily-lexer.hh +++ b/lily/include/lily-lexer.hh @@ -34,7 +34,9 @@ private: Keyword_table *keytable_; SCM scopes_; SCM start_module_; + int hidden_state_; public: + vector extra_token_types_; string main_input_name_; void *lexval; Input *lexloc; @@ -67,6 +69,7 @@ public: SCM lookup_identifier (string s); SCM lookup_identifier_symbol (SCM s); + void push_extra_token (int token_type); void push_chord_state (SCM tab); void push_figuredbass_state (); void push_lyric_state (); @@ -76,6 +79,7 @@ public: void pop_state (); void LexerError (char const *); void set_identifier (SCM name_string, SCM); + int get_state () const; bool is_note_state () const; bool is_chord_state () const; bool is_lyric_state () const; diff --git a/lily/lexer.ll b/lily/lexer.ll index 178ea88e97..9d333ff511 100644 --- a/lily/lexer.ll +++ b/lily/lexer.ll @@ -43,6 +43,7 @@ using namespace std; #include "lily-lexer.hh" #include "lilypond-input-version.hh" #include "main.hh" +#include "music.hh" #include "music-function.hh" #include "parse-scm.hh" #include "parser.hh" @@ -60,7 +61,6 @@ RH 7 fix (?) void strip_trailing_white (string&); void strip_leading_white (string&); string lyric_fudge (string s); -int music_function_type (SCM); SCM lookup_markup_command (string s); bool is_valid_version (string s); @@ -103,6 +103,7 @@ SCM (* scm_parse_error_handler) (void *); %option never-interactive %option warn +%x extratoken %x chords %x figures %x incl @@ -120,6 +121,7 @@ A [a-zA-Z] AA {A}|_ N [0-9] AN {AA}|{N} +ANY_CHAR (.|\n) PUNCT [?!:'`] ACCENT \\[`'"^] NATIONAL [\001-\006\021-\027\031\036\200-\377] @@ -153,6 +155,22 @@ BOM_UTF8 \357\273\277 // windows-suck-suck-suck } +{ANY_CHAR} { + /* Generate a token without swallowing anything */ + + /* First unswallow the eaten character */ + add_lexed_char (-YYLeng ()); + yyless (0); + + /* produce requested token */ + int type = extra_token_types_.back (); + extra_token_types_.pop_back (); + if (extra_token_types_.empty ()) + yy_pop_state (); + + return type; +} + {BOM_UTF8} { if (this->lexloc->line_number () != 1 || this->lexloc->column_number () != 0) { @@ -647,6 +665,20 @@ BOM_UTF8 \357\273\277 %% +/* Make the lexer generate a token of the given type as the next token. + TODO: make it possible to define a value for the token as well */ +void +Lily_lexer::push_extra_token (int token_type) +{ + if (extra_token_types_.empty ()) + { + if (YY_START != extratoken) + hidden_state_ = YY_START; + yy_push_state (extratoken); + } + extra_token_types_.push_back (token_type); +} + void Lily_lexer::push_chord_state (SCM tab) { @@ -690,6 +722,7 @@ Lily_lexer::pop_state () { if (YYSTATE == notes || YYSTATE == chords) pitchname_tab_stack_ = scm_cdr (pitchname_tab_stack_); + yy_pop_state (); } @@ -718,7 +751,19 @@ Lily_lexer::scan_escaped_word (string str) if (is_music_function (sid)) { yylval.scm = get_music_function_transform (sid); - return music_function_type (yylval.scm); + + SCM s = scm_object_property (yylval.scm, ly_symbol2scm ("music-function-signature")); + for (; scm_is_pair (s); s = scm_cdr (s)) + { + if (scm_car (s) == ly_music_p_proc) + push_extra_token (EXPECT_MUSIC); + else if (scm_car (s) == ly_lily_module_constant ("markup?")) + push_extra_token (EXPECT_MARKUP); + else if (ly_is_procedure (scm_car (s))) + push_extra_token (EXPECT_SCM); + else programming_error ("Function parameter without type-checking predicate"); + } + return MUSIC_FUNCTION; } if (sid != SCM_UNDEFINED) @@ -762,28 +807,37 @@ Lily_lexer::scan_bare_word (string str) return STRING; } +int +Lily_lexer::get_state () const +{ + if (YY_START == extratoken) + return hidden_state_; + else + return YY_START; +} + bool Lily_lexer::is_note_state () const { - return YY_START == notes; + return get_state () == notes; } bool Lily_lexer::is_chord_state () const { - return YY_START == chords; + return get_state () == chords; } bool Lily_lexer::is_lyric_state () const { - return YY_START == lyrics; + return get_state () == lyrics; } bool Lily_lexer::is_figure_state () const { - return YY_START == figures; + return get_state () == figures; } /* @@ -881,59 +935,6 @@ lookup_markup_command (string s) return scm_call_1 (proc, scm_makfrom0str (s.c_str ())); } -struct Parser_signature -{ - char *symbol; - int token_type; -}; -static SCM signature_hash_table; - -static void init_signature_hash_table () -{ - signature_hash_table = scm_gc_protect_object (scm_c_make_hash_table (31)); - Parser_signature sigs[] = { - {"scm", MUSIC_FUNCTION_SCM}, - {"music", MUSIC_FUNCTION_MUSIC}, - {"scm-music", MUSIC_FUNCTION_SCM_MUSIC}, - {"scm-scm", MUSIC_FUNCTION_SCM_SCM}, - {"music-music", MUSIC_FUNCTION_MUSIC_MUSIC}, - {"scm-music-music", MUSIC_FUNCTION_SCM_MUSIC_MUSIC}, - {"scm-scm-music-music", MUSIC_FUNCTION_SCM_SCM_MUSIC_MUSIC}, - {"scm-scm-music", MUSIC_FUNCTION_SCM_SCM_MUSIC}, - {"scm-scm-scm-music", MUSIC_FUNCTION_SCM_SCM_SCM_SCM_MUSIC}, - {"scm-scm-scm-scm-music", MUSIC_FUNCTION_SCM_SCM_SCM_MUSIC}, - {"scm-scm-scm", MUSIC_FUNCTION_SCM_SCM_SCM}, - {"markup", MUSIC_FUNCTION_MARKUP}, - {"markup-music", MUSIC_FUNCTION_MARKUP_MUSIC}, - {"markup-markup", MUSIC_FUNCTION_MARKUP_MARKUP}, - {"markup-music-music", MUSIC_FUNCTION_MARKUP_MUSIC_MUSIC}, - {"markup-markup-music", MUSIC_FUNCTION_MARKUP_MARKUP_MUSIC}, - {"noarg", MUSIC_FUNCTION}, - {0,0} - }; - - for (int i = 0; sigs[i].symbol; i++) - scm_hashq_set_x (signature_hash_table, ly_symbol2scm (sigs[i].symbol), - scm_from_int (sigs[i].token_type)); -} - -int -music_function_type (SCM func) -{ - if (!signature_hash_table) - init_signature_hash_table (); - - SCM type = scm_object_property (func, ly_symbol2scm ("music-function-signature-keyword")); - SCM token_type = scm_hashq_ref (signature_hash_table, type, SCM_BOOL_F); - if (!scm_is_number (token_type)) - { - programming_error (_ ("can't find signature for music function")); - return MUSIC_FUNCTION_SCM; - } - - return scm_to_int (token_type); -} - /* Shut up lexer warnings. */ #if YY_STACK_USED diff --git a/lily/music-function.cc b/lily/music-function.cc index 8f0f7813d9..c9b9a07658 100644 --- a/lily/music-function.cc +++ b/lily/music-function.cc @@ -35,26 +35,9 @@ LY_DEFINE (ly_make_music_function, "ly:make-music-function", 2, 0, 0, { extern SCM ly_music_p_proc; - string str = ""; - for (SCM s = signature; scm_is_pair (s); s = scm_cdr (s)) - { - if (str != "") - str += "-"; - - if (scm_car (s) == ly_music_p_proc) - str += "music"; - else if (scm_car (s) == ly_lily_module_constant ("markup?")) - str += "markup"; - else if (ly_is_procedure (scm_car (s))) - str += "scm"; - } - if (str == "") str = "noarg"; scm_set_object_property_x (func, ly_symbol2scm ("music-function-signature"), signature); - scm_set_object_property_x (func, ly_symbol2scm ("music-function-signature-keyword"), - ly_symbol2scm (str.c_str ())); - SCM_RETURN_NEWSMOB (music_function_tag, func); } diff --git a/lily/parser.yy b/lily/parser.yy index ef215c327a..3f06738a64 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -256,6 +256,11 @@ If we give names, Bison complains. %token E_UNSIGNED %token UNSIGNED +/* Artificial tokens, for more generic function syntax */ +%token EXPECT_MARKUP; +%token EXPECT_MUSIC; +%token EXPECT_SCM; + %token BOOK_IDENTIFIER %token CHORDMODIFIER_PITCH %token CHORD_MODIFIER @@ -277,22 +282,6 @@ If we give names, Bison complains. %token MARKUP_HEAD_SCM0_SCM1_SCM2 %token MARKUP_IDENTIFIER %token MUSIC_FUNCTION -%token MUSIC_FUNCTION_MARKUP -%token MUSIC_FUNCTION_MARKUP_MARKUP -%token MUSIC_FUNCTION_MARKUP_MARKUP_MUSIC -%token MUSIC_FUNCTION_MARKUP_MUSIC -%token MUSIC_FUNCTION_MARKUP_MUSIC_MUSIC -%token MUSIC_FUNCTION_MUSIC -%token MUSIC_FUNCTION_MUSIC_MUSIC -%token MUSIC_FUNCTION_SCM -%token MUSIC_FUNCTION_SCM_MUSIC -%token MUSIC_FUNCTION_SCM_MUSIC_MUSIC -%token MUSIC_FUNCTION_SCM_SCM_MUSIC_MUSIC -%token MUSIC_FUNCTION_SCM_SCM -%token MUSIC_FUNCTION_SCM_SCM_MUSIC -%token MUSIC_FUNCTION_SCM_SCM_SCM -%token MUSIC_FUNCTION_SCM_SCM_SCM_MUSIC -%token MUSIC_FUNCTION_SCM_SCM_SCM_SCM_MUSIC %token MUSIC_IDENTIFIER %token NOTENAME_PITCH %token NUMBER_IDENTIFIER @@ -361,10 +350,6 @@ If we give names, Bison complains. %type absolute_pitch %type assignment_id %type bare_number -%type music_function_event -%type music_function_chord_body -%type music_function_musicless_prefix -%type music_function_musicless_function %type bass_figure %type figured_bass_modification %type br_bass_figure @@ -386,6 +371,11 @@ If we give names, Bison complains. %type figure_spec %type fraction %type full_markup +%type function_scm_argument +%type function_arglist +%type function_arglist_music_last +%type function_arglist_nonmusic_last +%type function_arglist_nonmusic %type identifier_init %type lilypond_header %type lilypond_header_body @@ -402,6 +392,9 @@ If we give names, Bison complains. %type mode_changing_head %type mode_changing_head_with_context %type multiplied_duration +%type music_function_identifier_musicless_prefix +%type music_function_event +%type music_function_chord_body %type new_chord %type new_lyrics %type number_expression @@ -427,7 +420,6 @@ If we give names, Bison complains. %type step_number %type step_numbers %type string -%type function_scm_argument %type score_block %type score_body @@ -925,72 +917,46 @@ 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: /*empty*/ { + $$ = 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: /*empty*/ { + $$ = 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)); } ; @@ -1397,24 +1363,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 {