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--2021 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 SCM s = Display::value_to_lily_string (value); \ 45 char *p = scm_to_locale_string (s); \ 46 fputs (p, file); \ 47 free (p); \ 48 } while (0) 49 50 51#define lookup_identifier(x) lookup_identifier_symbol (ly_symbol2scm (x)) 52 53%} 54 55%parse-param {Lily_parser *parser} 56%parse-param {SCM *retval} 57%lex-param {Lily_parser *parser} 58%define parse.error verbose 59%debug 60 61/* We use SCMs to do strings, because it saves us the trouble of 62deleting them. Let's hope that a stack overflow doesn't trigger a move 63of the parse stack onto the heap. */ 64 65%left PREC_BOT 66%nonassoc REPEAT 67%nonassoc ALTERNATIVE 68 69/* The above precedences tackle the shift/reduce problem 70 711. \repeat 72 \repeat .. \alternative 73 74 \repeat { \repeat .. \alternative } 75 76or 77 78 \repeat { \repeat } \alternative 79*/ 80 81%nonassoc COMPOSITE 82%left ADDLYRICS 83 84%right ':' UNSIGNED REAL E_UNSIGNED EVENT_IDENTIFIER EVENT_FUNCTION '^' '_' 85 HYPHEN EXTENDER DURATION_IDENTIFIER '!' '\'' ',' 86 87 /* The above are needed for collecting tremoli and other items (that 88 could otherwise be interpreted as belonging to the next function 89 argument) greedily, and together with the next rule will serve to 90 join numbers and units greedily instead of allowing them into 91 separate function arguments 92 */ 93 94%nonassoc NUMBER_IDENTIFIER 95 96%left PREC_TOP 97 98%define api.pure full 99%locations 100 101%{ // -*-Fundamental-*- 102 103/* 104FIXME: 105 106 * The rules for who is protecting what are very shady. Uniformise 107 this. 108 109 * There are too many lexical modes? 110*/ 111 112#include "config.hh" 113 114#include <cctype> 115#include <cstdlib> 116#include <cstdio> 117 118#include "book.hh" 119#include "context.hh" 120#include "context-def.hh" 121#include "context-mod.hh" 122#include "dimensions.hh" 123#include "file-path.hh" 124#include "input.hh" 125#include "international.hh" 126#include "lily-guile.hh" 127#include "lily-lexer.hh" 128#include "lily-parser.hh" 129#include "ly-module.hh" 130#include "ly-scm-list.hh" 131#include "misc.hh" 132#include "music.hh" 133#include "output-def.hh" 134#include "scm-hash.hh" 135#include "score.hh" 136#include "std-vector.hh" 137#include "text-interface.hh" 138#include "warn.hh" 139#include "lily-imports.hh" 140 141void 142Lily_parser::parser_error (Input const *i, Lily_parser *parser, SCM *, const std::string &s) 143{ 144 parser->parser_error (*i, s); 145} 146 147// The following are somewhat precarious constructs as they may change 148// the value of the lookahead token. That implies that the lookahead 149// token must not yet have made an impact on the state stack other 150// than causing the reduction of the current rule, or switching the 151// lookahead token while Bison is mulling it over will cause trouble. 152 153#define MYBACKUP(Token, Value, Location) \ 154 do { \ 155 if (yychar != YYEMPTY) \ 156 parser->lexer_->push_extra_token \ 157 (yylloc, yychar, yylval); \ 158 parser->lexer_->push_extra_token \ 159 (Location, Token, Value); \ 160 parser->lexer_->push_extra_token (Location, BACKUP); \ 161 yychar = YYEMPTY; \ 162 } while (0) 163 164 165#define MYREPARSE(Location, Pred, Token, Value) \ 166 do { \ 167 if (yychar != YYEMPTY) \ 168 parser->lexer_->push_extra_token \ 169 (yylloc, yychar, yylval); \ 170 parser->lexer_->push_extra_token \ 171 (Location, Token, Value); \ 172 parser->lexer_->push_extra_token \ 173 (Location, REPARSE, Pred); \ 174 yychar = YYEMPTY; \ 175 } while (0) 176 177%} 178 179 180%{ 181 182#define MY_MAKE_MUSIC(x, spot) \ 183 make_music_with_input (ly_symbol2scm (x), \ 184 parser->lexer_->override_input (spot)) 185 186/* ES TODO: 187- delay application of the function 188*/ 189 190#define LOWLEVEL_MAKE_SYNTAX(location, proc, ...) \ 191 with_location \ 192 (parser->lexer_->override_input (location).smobbed_copy (), \ 193 proc, \ 194 ##__VA_ARGS__) 195 196/* Syntactic Sugar. */ 197#define MAKE_SYNTAX(name, location, ...) \ 198 LOWLEVEL_MAKE_SYNTAX (location, Syntax::name, ##__VA_ARGS__) 199 200#define START_MAKE_SYNTAX(name, ...) \ 201 scm_list_n (Syntax::name, ##__VA_ARGS__, SCM_UNDEFINED) 202 203#define FINISH_MAKE_SYNTAX(start, location, ...) \ 204 LOWLEVEL_MAKE_SYNTAX \ 205 (location, \ 206 Guile_user::apply, \ 207 scm_car (start), \ 208 scm_append_x \ 209 (scm_list_2 (scm_cdr (start), \ 210 scm_list_n (__VA_ARGS__, SCM_UNDEFINED)))) 211 212#undef _ 213#if !HAVE_GETTEXT 214#define _(x) x 215#else 216#include <libintl.h> 217#define _(x) gettext (x) 218#endif 219 220using std::string; 221 222static Music *make_music_with_input (SCM name, Input where); 223bool add_post_events (Music *music, SCM events); 224SCM reverse_music_list (Lily_parser *parser, Input loc, SCM lst, bool preserve, bool compress); 225SCM check_scheme_arg (Lily_parser *parser, Input loc, 226 SCM arg, SCM args, SCM pred, SCM disp = SCM_UNDEFINED); 227SCM make_music_from_simple (Lily_parser *parser, Input loc, SCM pitch); 228SCM loc_on_copy (Lily_parser *parser, Input loc, SCM arg); 229SCM make_chord_elements (Input loc, SCM pitch, SCM dur, SCM modification_list); 230SCM make_chord_step (SCM step, Rational alter); 231SCM make_simple_markup (SCM a); 232SCM make_duration (SCM t, int dots = 0, SCM factor = SCM_UNDEFINED); 233bool is_regular_identifier (SCM id, bool multiple=false); 234SCM make_reverse_key_list (SCM keys); 235SCM try_word_variants (SCM pred, SCM str); 236SCM try_string_variants (SCM pred, SCM str); 237SCM post_event_cons (SCM ev, SCM tail); 238int yylex (YYSTYPE *s, YYLTYPE *loc, Lily_parser *parser); 239 240// generated code may trigger conversion warnings 241#pragma GCC diagnostic ignored "-Wconversion" 242 243// generated code triggers a false positive in GCC 11 244// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98753 245#pragma GCC diagnostic ignored "-Wfree-nonheap-object" 246 247// generated code contains some old-style casts 248#pragma GCC diagnostic ignored "-Wold-style-cast" 249 250// generated code contains some useless casts 251#pragma GCC diagnostic ignored "-Wuseless-cast" 252 253%} 254 255/* The third option is an alias that will be used to display the 256 syntax error. Bison CVS now correctly handles backslash escapes. 257 258 FIXME: Bison needs to translate some of these, eg, STRING. 259 260*/ 261 262/* Keyword tokens with plain escaped name. */ 263%token END_OF_FILE 0 "end of input" 264%token ACCEPTS "\\accepts" 265%token ADDLYRICS "\\addlyrics" 266%token ALIAS "\\alias" 267%token ALTERNATIVE "\\alternative" 268%token BOOK "\\book" 269%token BOOKPART "\\bookpart" 270%token CHANGE "\\change" 271%token CHORDMODE "\\chordmode" 272%token CHORDS "\\chords" 273%token CONSISTS "\\consists" 274%token CONTEXT "\\context" 275%token DEFAULT "\\default" 276%token DEFAULTCHILD "\\defaultchild" 277%token DENIES "\\denies" 278%token DESCRIPTION "\\description" 279%token DRUMMODE "\\drummode" 280%token DRUMS "\\drums" 281%token ETC "\\etc" 282%token FIGUREMODE "\\figuremode" 283%token FIGURES "\\figures" 284%token HEADER "\\header" 285%token INVALID "\\version-error" 286%token LAYOUT "\\layout" 287%token LYRICMODE "\\lyricmode" 288%token LYRICS "\\lyrics" 289%token LYRICSTO "\\lyricsto" 290%token MARKUP "\\markup" 291%token MARKUPLIST "\\markuplist" 292%token MIDI "\\midi" 293%token NAME "\\name" 294%token NOTEMODE "\\notemode" 295%token OVERRIDE "\\override" 296%token PAPER "\\paper" 297%token REMOVE "\\remove" 298%token REPEAT "\\repeat" 299%token REST "\\rest" 300%token REVERT "\\revert" 301%token SCORE "\\score" 302%token SCORELINES "\\score-lines" 303%token SEQUENTIAL "\\sequential" 304%token SET "\\set" 305%token SIMULTANEOUS "\\simultaneous" 306%token TEMPO "\\tempo" 307%token TYPE "\\type" 308%token UNSET "\\unset" 309%token WITH "\\with" 310 311/* Keyword token exceptions. */ 312%token NEWCONTEXT "\\new" 313 314 315/* Other string tokens. */ 316 317%token CHORD_BASS "/+" 318%token CHORD_CARET "^" 319%token CHORD_COLON ":" 320%token CHORD_MINUS "-" 321%token CHORD_SLASH "/" 322%token ANGLE_OPEN "<" 323%token ANGLE_CLOSE ">" 324%token DOUBLE_ANGLE_OPEN "<<" 325%token DOUBLE_ANGLE_CLOSE ">>" 326%token E_BACKSLASH "\\\\" 327%token E_EXCLAMATION "\\!" 328%token E_PLUS "\\+" 329%token EXTENDER "__" 330 331/* 332If we give names, Bison complains. 333*/ 334%token FIGURE_CLOSE /* "\\>" */ 335%token FIGURE_OPEN /* "\\<" */ 336%token FIGURE_SPACE "_" 337%token FIGURE_ALTERATION_EXPR 338%token HYPHEN "--" 339 340%token MULTI_MEASURE_REST 341 342 343%token E_UNSIGNED 344%token UNSIGNED 345 346/* Artificial tokens, for more generic function syntax */ 347%token EXPECT_MARKUP "markup?" 348%token EXPECT_SCM "scheme?" 349%token BACKUP "(backed-up?)" 350%token REPARSE "(reparsed?)" 351%token EXPECT_MARKUP_LIST "markup-list?" 352%token EXPECT_OPTIONAL "optional?" 353/* After the last argument. */ 354%token EXPECT_NO_MORE_ARGS; 355 356/* An artificial token for parsing embedded Lilypond */ 357%token EMBEDDED_LILY "#{" 358 359%token BOOK_IDENTIFIER 360%token CHORD_MODIFIER 361%token CHORD_REPETITION 362%token DRUM_PITCH 363 /* Artificial token for durations in argument lists */ 364%token DURATION_ARG 365%token DURATION_IDENTIFIER 366%token EVENT_IDENTIFIER 367%token EVENT_FUNCTION 368%token FRACTION 369%token LOOKUP_IDENTIFIER 370%token LYRIC_ELEMENT 371%token MARKUP_FUNCTION 372%token MARKUP_LIST_FUNCTION 373%token MARKUP_IDENTIFIER 374%token MARKUPLIST_IDENTIFIER 375%token MUSIC_FUNCTION 376%token MUSIC_IDENTIFIER 377%token NOTENAME_PITCH 378%token NUMBER_IDENTIFIER 379%token PITCH_IDENTIFIER 380%token REAL 381%token RESTNAME 382%token SCM_ARG 383%token SCM_FUNCTION 384%token SCM_IDENTIFIER 385%token SCM_TOKEN 386%token STRING 387%token SYMBOL_LIST 388%token TONICNAME_PITCH 389%token SYMBOL 390 391%left '-' '+' 392 393/* We don't assign precedence to / and *, because we might need varied 394prec levels in different prods */ 395 396%left UNARY_MINUS 397 398%% 399 400start_symbol: 401 lilypond 402 | EMBEDDED_LILY { 403 parser->lexer_->push_note_state (); 404 } embedded_lilypond { 405 parser->lexer_->pop_state (); 406 *retval = $3; 407 } 408 ; 409 410lilypond: /* empty */ { $$ = SCM_UNSPECIFIED; } 411 | lilypond toplevel_expression { 412 } 413 | lilypond assignment { 414 } 415 | lilypond error { 416 parser->error_level_ = 1; 417 } 418 | lilypond INVALID { 419 parser->error_level_ = 1; 420 } 421 ; 422 423 424toplevel_expression: 425 header_block { 426 parser->lexer_->set_identifier (ly_symbol2scm ("$defaultheader"), $1); 427 } 428 | book_block { 429 SCM proc = parser->lexer_->lookup_identifier ("toplevel-book-handler"); 430 scm_call_1 (proc, $1); 431 } 432 | bookpart_block { 433 SCM proc = parser->lexer_->lookup_identifier ("toplevel-bookpart-handler"); 434 scm_call_1 (proc, $1); 435 } 436 | BOOK_IDENTIFIER { 437 SCM sym = unsmob<Book>($1)->paper_ 438 ? ly_symbol2scm ("toplevel-book-handler") 439 : ly_symbol2scm ("toplevel-bookpart-handler"); 440 441 SCM proc = parser->lexer_->lookup_identifier_symbol (sym); 442 scm_call_1 (proc, $1); 443 } 444 | score_block { 445 SCM proc = parser->lexer_->lookup_identifier ("toplevel-score-handler"); 446 scm_call_1 (proc, $1); 447 } 448 | composite_music { 449 SCM proc = parser->lexer_->lookup_identifier ("toplevel-music-handler"); 450 scm_call_1 (proc, $1); 451 } 452 | full_markup { 453 SCM proc = parser->lexer_->lookup_identifier ("toplevel-text-handler"); 454 scm_call_1 (proc, scm_list_1 ($1)); 455 } 456 | full_markup_list { 457 SCM proc = parser->lexer_->lookup_identifier ("toplevel-text-handler"); 458 scm_call_1 (proc, $1); 459 } 460 | SCM_TOKEN { 461 // Evaluate and ignore #xxx, as opposed to \xxx 462 parser->lexer_->eval_scm_token ($1, @1); 463 } 464 | embedded_scm_active 465 { 466 SCM out = SCM_UNDEFINED; 467 if (Text_interface::is_markup ($1)) 468 out = scm_list_1 ($1); 469 else if (Text_interface::is_markup_list ($1)) 470 out = $1; 471 if (scm_is_pair (out)) 472 { 473 SCM proc = parser->lexer_->lookup_identifier ("toplevel-text-handler"); 474 scm_call_1 (proc, out); 475 } else if (unsmob<Score> ($1)) 476 { 477 SCM proc = parser->lexer_->lookup_identifier ("toplevel-score-handler"); 478 scm_call_1 (proc, $1); 479 } else if (Output_def * od = unsmob<Output_def> ($1)) { 480 SCM id = SCM_EOL; 481 482 if (from_scm<bool> (od->c_variable ("is-paper"))) 483 id = ly_symbol2scm ("$defaultpaper"); 484 else if (from_scm<bool> (od->c_variable ("is-midi"))) 485 id = ly_symbol2scm ("$defaultmidi"); 486 else if (from_scm<bool> (od->c_variable ("is-layout"))) 487 id = ly_symbol2scm ("$defaultlayout"); 488 489 parser->lexer_->set_identifier (id, $1); 490 } else if (ly_is_module ($1)) 491 { 492 SCM module = get_header (parser); 493 ly_module_copy (module, $1); 494 parser->lexer_->set_identifier 495 (ly_symbol2scm ("$defaultheader"), module); 496 } else if (!scm_is_eq ($1, SCM_UNSPECIFIED)) 497 parser->parser_error (@1, _("bad expression type")); 498 } 499 | output_def { 500 SCM id = SCM_EOL; 501 Output_def * od = unsmob<Output_def> ($1); 502 503 if (from_scm<bool> (od->c_variable ("is-paper"))) 504 id = ly_symbol2scm ("$defaultpaper"); 505 else if (from_scm<bool> (od->c_variable ("is-midi"))) 506 id = ly_symbol2scm ("$defaultmidi"); 507 else if (from_scm<bool> (od->c_variable ("is-layout"))) 508 id = ly_symbol2scm ("$defaultlayout"); 509 510 parser->lexer_->set_identifier (id, $1); 511 } 512 ; 513 514lookup: 515 LOOKUP_IDENTIFIER 516 | LOOKUP_IDENTIFIER '.' symbol_list_rev 517 { 518 $$ = loc_on_copy (parser, @$, 519 nested_property ($1, scm_reverse_x ($3, SCM_EOL))); 520 } 521 ; 522 523embedded_scm_bare: 524 SCM_TOKEN 525 { 526 $$ = parser->lexer_->eval_scm_token ($1, @1); 527 } 528 | SCM_IDENTIFIER 529 ; 530 531embedded_scm_active: 532 SCM_IDENTIFIER 533 | scm_function_call 534 | lookup 535 ; 536 537embedded_scm_bare_arg: 538 SCM_ARG 539 | SCM_TOKEN 540 { 541 $$ = parser->lexer_->eval_scm_token ($1, @1); 542 } 543 | FRACTION 544 | partial_markup 545 | full_markup_list 546 | context_modification 547 | header_block 548 | score_block 549 | context_def_spec_block 550 | book_block 551 | bookpart_block 552 | output_def 553 | lookup 554 ; 555 556/* The generic version may end in music, or not */ 557 558embedded_scm: 559 embedded_scm_bare 560 | scm_function_call 561 | lookup 562 ; 563 564/* embedded_scm_arg is _not_ casting pitches to music by default, this 565 * has to be done by the function itself. Note that this may cause 566 * the results of scm_function_call or embedded_scm_bare_arg to be 567 * turned into music from pitches as well. Note that this creates a 568 * distinctly awkward situation for calculated drum pitches. Those 569 * are at the current point of time rejected as music constituents as 570 * they can't be distinguished from "proper" symbols. 571 */ 572 573embedded_scm_arg: 574 embedded_scm_bare_arg 575 | scm_function_call 576 | music_assign 577 ; 578 579scm_function_call: 580 SCM_FUNCTION function_arglist { 581 $$ = MAKE_SYNTAX (music_function, @$, 582 $1, $2); 583 } 584 ; 585 586embedded_lilypond_number: 587 '-' embedded_lilypond_number 588 { 589 $$ = scm_difference ($2, SCM_UNDEFINED); 590 } 591 | bare_number_common 592 | UNSIGNED NUMBER_IDENTIFIER 593 { 594 $$ = scm_product ($1, $2); 595 } 596 ; 597 598embedded_lilypond: 599 /* empty */ 600 { 601 // FIXME: @$ does not contain a useful source location 602 // for empty rules, and the only token in the whole 603 // production, EMBEDDED_LILY, is synthetic and also 604 // contains no source location. 605 $$ = MAKE_SYNTAX (void_music, @$); 606 } 607 | identifier_init_nonumber 608 | embedded_lilypond_number 609 | post_event 610 { 611 if (!unsmob<Music> ($1)) 612 $$ = MY_MAKE_MUSIC ("PostEvents", @$)->unprotect (); 613 } 614 | duration post_events %prec ':' 615 { 616 if (scm_is_pair ($2)) { 617 Music *n = MY_MAKE_MUSIC ("NoteEvent", @$); 618 619 parser->default_duration_ = *unsmob<Duration> ($1); 620 set_property (n, "duration", $1); 621 set_property (n, "articulations", 622 scm_reverse_x ($2, SCM_EOL)); 623 $$ = n->unprotect (); 624 } 625 } 626 | music_embedded music_embedded music_list { 627 SCM tail = SCM_EOL; 628 if (unsmob<Music> ($1)) 629 tail = scm_cons ($1, tail); 630 if (unsmob<Music> ($2)) 631 tail = scm_cons ($2, tail); 632 $$ = reverse_music_list (parser, @$, 633 scm_append_x (scm_list_2 ($3, tail)), 634 true, true); 635 if (scm_is_pair ($$)) // unpackaged list 636 if (scm_is_null (scm_cdr ($$))) 637 $$ = scm_car ($$); // single expression 638 else 639 $$ = MAKE_SYNTAX (sequential_music, @$, $$); 640 else if (scm_is_null ($$)) 641 $$ = MAKE_SYNTAX (void_music, @$); 642 // else already packaged post-event 643 } 644 | error { 645 parser->error_level_ = 1; 646 $$ = SCM_UNSPECIFIED; 647 } 648 | INVALID embedded_lilypond { 649 parser->error_level_ = 1; 650 $$ = $2; 651 } 652 ; 653 654 655lilypond_header_body: 656 /* empty */ { $$ = SCM_UNSPECIFIED; } 657 | lilypond_header_body assignment { 658 659 } 660 | lilypond_header_body SCM_TOKEN { 661 // Evaluate and ignore #xxx, as opposed to \xxx 662 parser->lexer_->eval_scm_token ($2, @2); 663 } 664 | lilypond_header_body embedded_scm_active { 665 if (ly_is_module ($2)) 666 ly_module_copy (scm_current_module (), $2); 667 else if (!scm_is_eq ($2, SCM_UNSPECIFIED)) 668 parser->parser_error (@2, _("bad expression type")); 669 } 670 ; 671 672lilypond_header: 673 HEADER '{' lilypond_header_body '}' { 674 $$ = parser->lexer_->remove_scope (); 675 } 676 ; 677 678header_block: 679 { 680 parser->lexer_->add_scope (get_header (parser)); 681 } lilypond_header { 682 $$ = $2; 683 } 684 ; 685 686/* 687 DECLARATIONS 688*/ 689assignment_id: 690 STRING 691 { 692 $$ = scm_string_to_symbol ($1); 693 } 694 | SYMBOL 695 { 696 $$ = scm_string_to_symbol ($1); 697 } 698 ; 699 700assignment: 701 assignment_id '=' identifier_init { 702 parser->lexer_->set_identifier ($1, $3); 703 $$ = SCM_UNSPECIFIED; 704 } 705 | assignment_id '.' property_path '=' identifier_init { 706 SCM path = scm_cons ($1, $3); 707 parser->lexer_->set_identifier (path, $5); 708 $$ = SCM_UNSPECIFIED; 709 } 710 | markup_mode_word '=' identifier_init 711 { 712 if (scm_is_false (Lily::markup_function_p ($3))) 713 { 714 parser->parser_error (@3, _ ("Not a markup function")); 715 } else { 716 Lily::define_markup_command_internal 717 (scm_string_to_symbol ($1), $3, SCM_BOOL_F); 718 } 719 $$ = SCM_UNSPECIFIED; 720 } 721 ; 722 723 724identifier_init: 725 identifier_init_nonumber 726 | number_expression 727 | symbol_list_part_bare '.' property_path 728 { 729 $$ = scm_reverse_x ($1, $3); 730 } 731 | symbol_list_part_bare ',' property_path 732 { 733 $$ = scm_reverse_x ($1, $3); 734 } 735 | post_event_nofinger post_events 736 { 737 $$ = post_event_cons ($1, scm_reverse_x ($2, SCM_EOL)); 738 if (scm_is_pair ($$) 739 && scm_is_null (scm_cdr ($$))) 740 $$ = scm_car ($$); 741 else 742 { 743 Music * m = MY_MAKE_MUSIC ("PostEvents", @$); 744 set_property (m, "elements", $$); 745 $$ = m->unprotect (); 746 } 747 } 748 ; 749 750identifier_init_nonumber: 751 header_block 752 | score_block 753 | book_block 754 | bookpart_block 755 | output_def 756 | context_def_spec_block 757 | music_assign 758 | pitch_or_music 759 | FRACTION 760 | string 761 | embedded_scm 762 | partial_markup 763 | full_markup_list 764 | context_modification 765 | partial_function ETC 766 { 767 $$ = MAKE_SYNTAX (partial_music_function, @$, 768 scm_reverse_x ($1, SCM_EOL)); 769 } 770 ; 771 772// Partial functions 773 774partial_function_scriptable: 775 MUSIC_FUNCTION function_arglist_partial 776 { 777 $$ = scm_acons ($1, $2, SCM_EOL); 778 } 779 | EVENT_FUNCTION function_arglist_partial 780 { 781 $$ = scm_acons ($1, $2, SCM_EOL); 782 } 783 | SCM_FUNCTION function_arglist_partial 784 { 785 $$ = scm_acons ($1, $2, SCM_EOL); 786 } 787 | MUSIC_FUNCTION EXPECT_SCM function_arglist_optional partial_function 788 { 789 $$ = scm_acons ($1, $3, $4); 790 } 791 | EVENT_FUNCTION EXPECT_SCM function_arglist_optional partial_function 792 { 793 $$ = scm_acons ($1, $3, $4); 794 } 795 | SCM_FUNCTION EXPECT_SCM function_arglist_optional partial_function 796 { 797 $$ = scm_acons ($1, $3, $4); 798 } 799 | MUSIC_FUNCTION EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup partial_function 800 { 801 $$ = scm_acons ($1, $4, $5); 802 } 803 | EVENT_FUNCTION EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup partial_function 804 { 805 $$ = scm_acons ($1, $4, $5); 806 } 807 | SCM_FUNCTION EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup partial_function 808 { 809 $$ = scm_acons ($1, $4, $5); 810 } 811 ; 812 813partial_function: 814 partial_function_scriptable 815 | OVERRIDE grob_prop_path '=' 816 { 817 if (SCM_UNBNDP ($2)) 818 $$ = scm_list_1 (SCM_BOOL_F); 819 else 820 $$ = scm_cons 821 (scm_list_3 (Syntax::property_override, 822 scm_cdr ($2), scm_car ($2)), 823 SCM_EOL); 824 } 825 | SET context_prop_spec '=' 826 { 827 if (SCM_UNBNDP ($2)) 828 $$ = scm_list_1 (SCM_BOOL_F); 829 else 830 $$ = scm_cons 831 (scm_list_3 (Syntax::property_set, 832 scm_cadr ($2), scm_car ($2)), 833 SCM_EOL); 834 } 835 | OVERRIDE grob_prop_path '=' partial_function 836 { 837 if (SCM_UNBNDP ($2)) 838 $$ = scm_list_1 (SCM_BOOL_F); 839 else 840 $$ = scm_cons 841 (scm_list_3 (Syntax::property_override, 842 scm_cdr ($2), scm_car ($2)), 843 $4); 844 } 845 | SET context_prop_spec '=' partial_function 846 { 847 if (SCM_UNBNDP ($2)) 848 $$ = scm_list_1 (SCM_BOOL_F); 849 else 850 $$ = scm_cons 851 (scm_list_3 (Syntax::property_set, 852 scm_cadr ($2), scm_car ($2)), 853 $4); 854 } 855 | REPEAT simple_string unsigned_number 856 { 857 $$ = scm_cons (scm_list_3 (Syntax::repeat, $3, $2), SCM_EOL); 858 } 859 | REPEAT simple_string unsigned_number partial_function 860 { 861 $$ = scm_cons (scm_list_3 (Syntax::repeat, $3, $2), $4); 862 } 863 | REPEAT simple_string 864 { 865 $$ = scm_cons (scm_list_2 (Syntax::repeat, $2), SCM_EOL); 866 } 867 | REPEAT simple_string partial_function 868 { 869 $$ = scm_cons (scm_list_2 (Syntax::repeat, $2), $3); 870 } 871// Stupid duplication because we already expect ETC here. It will follow anyway. 872 | script_dir markup_mode markup_partial_function 873 { 874 if (SCM_UNBNDP ($1)) 875 $1 = SCM_INUM0; 876 $3 = MAKE_SYNTAX (partial_markup, @3, $3); 877 parser->lexer_->pop_state (); 878// This relies on partial_function always being followed by ETC 879 $$ = scm_list_1 (scm_list_3 (MAKE_SYNTAX (partial_text_script, @$, $3), 880 $3, $1)); 881 } 882 | script_dir partial_function_scriptable 883 { 884 if (SCM_UNBNDP ($1)) 885 $1 = SCM_INUM0; 886 $$ = scm_acons (Syntax::create_script_function, scm_list_1 ($1), $2); 887 } 888 | script_dir 889 { 890 if (SCM_UNBNDP ($1)) 891 $1 = SCM_INUM0; 892 $$ = scm_acons (Syntax::create_script_function, scm_list_1 ($1), SCM_EOL); 893 } 894 ; 895 896context_def_spec_block: 897 CONTEXT '{' context_def_spec_body '}' 898 { 899 $$ = $3; 900 Context_def *td = unsmob<Context_def> ($$); 901 if (!td) { 902 $$ = Context_def::make_scm (); 903 td = unsmob<Context_def> ($$); 904 } 905 td->origin ()->set_spot (@$); 906 } 907 ; 908 909context_mod_arg: 910 embedded_scm 911 | 912 { 913 parser->lexer_->push_note_state (); 914 } 915 composite_music 916 { 917 parser->lexer_->pop_state (); 918 $$ = $2; 919 } 920 ; 921 922 923context_def_spec_body: 924 /**/ { 925 $$ = SCM_UNSPECIFIED; 926 } 927 | context_def_spec_body context_mod { 928 if (!SCM_UNBNDP ($2)) { 929 Context_def *td = unsmob<Context_def> ($$); 930 if (!td) { 931 $$ = Context_def::make_scm (); 932 td = unsmob<Context_def> ($$); 933 } 934 unsmob<Context_def> ($$)->add_context_mod ($2); 935 } 936 } 937 | context_def_spec_body context_modification { 938 Context_def *td = unsmob<Context_def> ($$); 939 if (!td) { 940 $$ = Context_def::make_scm (); 941 td = unsmob<Context_def> ($$); 942 } 943 SCM new_mods = unsmob<Context_mod> ($2)->get_mods (); 944 for (SCM m = new_mods; scm_is_pair (m); m = scm_cdr (m)) { 945 td->add_context_mod (scm_car (m)); 946 } 947 } 948 | context_def_spec_body context_mod_arg { 949 Context_def *td = unsmob<Context_def> ($1); 950 if (scm_is_eq ($2, SCM_UNSPECIFIED)) 951 ; 952 else if (!td && unsmob<Context_def> ($2)) 953 $$ = $2; 954 else { 955 if (!td) { 956 $$ = Context_def::make_scm (); 957 td = unsmob<Context_def> ($$); 958 } 959 if (unsmob<Music> ($2)) { 960 SCM proc = parser->lexer_->lookup_identifier ("context-mod-music-handler"); 961 $2 = scm_call_1 (proc, $2); 962 } 963 if (Context_mod *cm = unsmob<Context_mod> ($2)) { 964 for (SCM m = cm->get_mods (); scm_is_pair (m); m = scm_cdr (m)) { 965 td->add_context_mod (scm_car (m)); 966 } 967 } else 968 parser->parser_error (@2, _ ("not a context mod")); 969 } 970 } 971 ; 972 973 974 975book_block: 976 BOOK '{' book_body '}' { 977 $$ = $3; 978 unsmob<Book> ($$)->origin ()->set_spot (@$); 979 pop_paper (parser); 980 parser->lexer_->set_identifier (ly_symbol2scm ("$current-book"), SCM_BOOL_F); 981 } 982 ; 983 984/* FIXME: 985 * Use 'handlers' like for toplevel-* stuff? 986 * grok \layout and \midi? */ 987book_body: 988 { 989 Book *book = new Book; 990 init_papers (parser); 991 book->paper_ = unsmob<Output_def> (parser->lexer_->lookup_identifier ("$defaultpaper"))->clone (); 992 book->paper_->unprotect (); 993 push_paper (parser, book->paper_); 994 book->header_ = get_header (parser); 995 $$ = book->unprotect (); 996 parser->lexer_->set_identifier (ly_symbol2scm ("$current-book"), $$); 997 } 998 | BOOK_IDENTIFIER { 999 parser->lexer_->set_identifier (ly_symbol2scm ("$current-book"), $1); 1000 } 1001 | book_body paper_block { 1002 unsmob<Book> ($1)->paper_ = unsmob<Output_def> ($2); 1003 set_paper (parser, unsmob<Output_def> ($2)); 1004 } 1005 | book_body bookpart_block { 1006 SCM proc = parser->lexer_->lookup_identifier ("book-bookpart-handler"); 1007 scm_call_2 (proc, $1, $2); 1008 } 1009 | book_body score_block { 1010 SCM proc = parser->lexer_->lookup_identifier ("book-score-handler"); 1011 scm_call_2 (proc, $1, $2); 1012 } 1013 | book_body composite_music { 1014 SCM proc = parser->lexer_->lookup_identifier ("book-music-handler"); 1015 scm_call_2 (proc, $1, $2); 1016 } 1017 | book_body full_markup { 1018 SCM proc = parser->lexer_->lookup_identifier ("book-text-handler"); 1019 scm_call_2 (proc, $1, scm_list_1 ($2)); 1020 } 1021 | book_body full_markup_list { 1022 SCM proc = parser->lexer_->lookup_identifier ("book-text-handler"); 1023 scm_call_2 (proc, $1, $2); 1024 } 1025 | book_body SCM_TOKEN { 1026 // Evaluate and ignore #xxx, as opposed to \xxx 1027 parser->lexer_->eval_scm_token ($2, @2); 1028 } 1029 | book_body embedded_scm_active 1030 { 1031 SCM out = SCM_UNDEFINED; 1032 if (Text_interface::is_markup ($2)) 1033 out = scm_list_1 ($2); 1034 else if (Text_interface::is_markup_list ($2)) 1035 out = $2; 1036 if (scm_is_pair (out)) 1037 { 1038 SCM proc = parser->lexer_->lookup_identifier ("book-text-handler"); 1039 scm_call_2 (proc, $1, out); 1040 } else if (unsmob<Score> ($2)) 1041 { 1042 SCM proc = parser->lexer_->lookup_identifier ("book-score-handler"); 1043 scm_call_2 (proc, $1, $2); 1044 } else if (Output_def *od = unsmob<Output_def> ($2)) { 1045 if (from_scm<bool> (od->lookup_variable (ly_symbol2scm ("is-paper")))) { 1046 unsmob<Book> ($1)->paper_ = od; 1047 set_paper (parser, od); 1048 } else { 1049 parser->parser_error (@2, _ ("need \\paper for paper block")); 1050 } 1051 } else if (ly_is_module ($2)) 1052 { 1053 ly_module_copy (unsmob<Book> ($1)->header_, $2); 1054 } else if (!scm_is_eq ($2, SCM_UNSPECIFIED)) 1055 parser->parser_error (@2, _("bad expression type")); 1056 } 1057 | book_body 1058 { 1059 parser->lexer_->add_scope (unsmob<Book> ($1)->header_); 1060 } lilypond_header 1061 | book_body error { 1062 Book *book = unsmob<Book> ($1); 1063 book->paper_ = 0; 1064 book->scores_ = SCM_EOL; 1065 book->bookparts_ = SCM_EOL; 1066 } 1067 ; 1068 1069bookpart_block: 1070 BOOKPART '{' bookpart_body '}' { 1071 $$ = $3; 1072 unsmob<Book> ($$)->origin ()->set_spot (@$); 1073 parser->lexer_->set_identifier (ly_symbol2scm ("$current-bookpart"), SCM_BOOL_F); 1074 } 1075 ; 1076 1077bookpart_body: 1078 { 1079 Book *book = new Book; 1080 $$ = book->unprotect (); 1081 parser->lexer_->set_identifier (ly_symbol2scm ("$current-bookpart"), $$); 1082 } 1083 | BOOK_IDENTIFIER { 1084 parser->lexer_->set_identifier (ly_symbol2scm ("$current-bookpart"), $1); 1085 } 1086 | bookpart_body paper_block { 1087 unsmob<Book> ($$)->paper_ = unsmob<Output_def> ($2); 1088 } 1089 | bookpart_body score_block { 1090 SCM proc = parser->lexer_->lookup_identifier ("bookpart-score-handler"); 1091 scm_call_2 (proc, $1, $2); 1092 } 1093 | bookpart_body composite_music { 1094 SCM proc = parser->lexer_->lookup_identifier ("bookpart-music-handler"); 1095 scm_call_2 (proc, $1, $2); 1096 } 1097 | bookpart_body full_markup { 1098 SCM proc = parser->lexer_->lookup_identifier ("bookpart-text-handler"); 1099 scm_call_2 (proc, $1, scm_list_1 ($2)); 1100 } 1101 | bookpart_body full_markup_list { 1102 SCM proc = parser->lexer_->lookup_identifier ("bookpart-text-handler"); 1103 scm_call_2 (proc, $1, $2); 1104 } 1105 | bookpart_body SCM_TOKEN { 1106 // Evaluate and ignore #xxx, as opposed to \xxx 1107 parser->lexer_->eval_scm_token ($2, @2); 1108 } 1109 | bookpart_body embedded_scm_active 1110 { 1111 SCM out = SCM_UNDEFINED; 1112 if (Text_interface::is_markup ($2)) 1113 out = scm_list_1 ($2); 1114 else if (Text_interface::is_markup_list ($2)) 1115 out = $2; 1116 if (scm_is_pair (out)) 1117 { 1118 SCM proc = parser->lexer_->lookup_identifier ("bookpart-text-handler"); 1119 scm_call_2 (proc, $1, out); 1120 } else if (unsmob<Score> ($2)) 1121 { 1122 SCM proc = parser->lexer_->lookup_identifier ("bookpart-score-handler"); 1123 scm_call_2 (proc, $1, $2); 1124 } else if (Output_def *od = unsmob<Output_def> ($2)) { 1125 if (from_scm<bool> (od->lookup_variable (ly_symbol2scm ("is-paper")))) { 1126 unsmob<Book> ($1)->paper_ = od; 1127 } else { 1128 parser->parser_error (@2, _ ("need \\paper for paper block")); 1129 } 1130 } else if (ly_is_module ($2)) { 1131 Book *book = unsmob<Book> ($1); 1132 if (!ly_is_module (book->header_)) 1133 book->header_ = ly_make_module (false); 1134 ly_module_copy (book->header_, $2); 1135 } else if (!scm_is_eq ($2, SCM_UNSPECIFIED)) 1136 parser->parser_error (@2, _("bad expression type")); 1137 } 1138 | bookpart_body 1139 { 1140 Book *book = unsmob<Book> ($1); 1141 if (!ly_is_module (book->header_)) 1142 book->header_ = ly_make_module (false); 1143 parser->lexer_->add_scope (book->header_); 1144 } lilypond_header 1145 | bookpart_body error { 1146 Book *book = unsmob<Book> ($1); 1147 book->paper_ = 0; 1148 book->scores_ = SCM_EOL; 1149 } 1150 ; 1151 1152score_block: 1153 SCORE '{' score_body '}' { 1154 unsmob<Score> ($3)->origin ()->set_spot (@$); 1155 $$ = $3; 1156 } 1157 ; 1158 1159score_body: 1160 score_items { 1161 if (!unsmob<Score> ($1)) { 1162 parser->parser_error (@1, _("Missing music in \\score")); 1163 $$ = (new Score)->unprotect (); 1164 if (scm_is_pair ($1) && ly_is_module (scm_car ($1))) 1165 { 1166 unsmob<Score> ($$)->set_header (scm_car ($1)); 1167 $1 = scm_cdr ($1); 1168 } 1169 for (SCM p = scm_reverse_x ($1, SCM_EOL); 1170 scm_is_pair (p); p = scm_cdr (p)) 1171 { 1172 unsmob<Score> ($$)-> 1173 add_output_def (unsmob<Output_def> (scm_car (p))); 1174 } 1175 } 1176 } 1177 | score_body error { 1178 unsmob<Score> ($$)->error_found_ = true; 1179 } 1180 ; 1181 1182score_item: 1183 embedded_scm 1184 | music 1185 | output_def 1186 ; 1187 1188score_items: 1189 /* empty */ 1190 { 1191 $$ = SCM_EOL; 1192 } 1193 | score_items score_item 1194 { 1195 Output_def *od = unsmob<Output_def> ($2); 1196 if (od) { 1197 if (from_scm<bool> (od->lookup_variable (ly_symbol2scm ("is-paper")))) 1198 { 1199 parser->parser_error (@2, _("\\paper cannot be used in \\score, use \\layout instead")); 1200 od = 0; 1201 $2 = SCM_UNSPECIFIED; 1202 } 1203 } else if (!unsmob<Score> ($$)) { 1204 if (unsmob<Music> ($2)) { 1205 $2 = Lily::scorify_music ($2); 1206 } 1207 if (unsmob<Score> ($2)) 1208 { 1209 $$ = $2; 1210 $2 = SCM_UNSPECIFIED; 1211 } 1212 } 1213 Score *score = unsmob<Score> ($$); 1214 if (score && scm_is_pair ($1)) { 1215 if (ly_is_module (scm_car ($1))) 1216 { 1217 score->set_header (scm_car ($1)); 1218 $1 = scm_cdr ($1); 1219 } 1220 for (SCM p = scm_reverse_x ($1, SCM_EOL); 1221 scm_is_pair (p); p = scm_cdr (p)) 1222 { 1223 score->add_output_def (unsmob<Output_def> (scm_car (p))); 1224 } 1225 } 1226 if (od) { 1227 if (score) 1228 score->add_output_def (od); 1229 else if (scm_is_pair ($$) && ly_is_module (scm_car ($$))) 1230 scm_set_cdr_x ($$, scm_cons ($2, scm_cdr ($$))); 1231 else 1232 $$ = scm_cons ($2, $$); 1233 } else if (ly_is_module ($2)) { 1234 SCM module = SCM_UNSPECIFIED; 1235 if (score) { 1236 module = score->get_header (); 1237 if (!ly_is_module (module)) 1238 { 1239 module = ly_make_module (false); 1240 score->set_header (module); 1241 } 1242 } else if (scm_is_pair ($$) && ly_is_module (scm_car ($$))) 1243 module = scm_car ($$); 1244 else { 1245 module = ly_make_module (false); 1246 $$ = scm_cons (module, $$); 1247 } 1248 ly_module_copy (module, $2); 1249 } else if (!scm_is_eq ($2, SCM_UNSPECIFIED)) 1250 parser->parser_error (@2, _("Spurious expression in \\score")); 1251 } 1252 | score_items 1253 { 1254 if (Score *score = unsmob<Score> ($1)) { 1255 if (!ly_is_module (score->get_header ())) 1256 score->set_header (ly_make_module (false)); 1257 parser->lexer_->add_scope (score->get_header ()); 1258 } else { 1259 if (!scm_is_pair ($1) || !ly_is_module (scm_car ($1))) 1260 $1 = scm_cons (ly_make_module (false), $1); 1261 parser->lexer_->add_scope (scm_car ($1)); 1262 } 1263 } lilypond_header 1264 { 1265 $$ = $1; 1266 } 1267 ; 1268 1269 1270/* 1271 OUTPUT DEF 1272*/ 1273 1274paper_block: 1275 output_def { 1276 Output_def *od = unsmob<Output_def> ($1); 1277 1278 if (!from_scm<bool> (od->lookup_variable (ly_symbol2scm ("is-paper")))) 1279 { 1280 parser->parser_error (@1, _ ("need \\paper for paper block")); 1281 $$ = get_paper (parser)->unprotect (); 1282 } 1283 } 1284 ; 1285 1286 1287output_def: 1288 output_def_body '}' { 1289 if (scm_is_pair ($1)) 1290 $$ = scm_car ($1); 1291 1292 parser->lexer_->remove_scope (); 1293 parser->lexer_->pop_state (); 1294 } 1295 ; 1296 1297output_def_head: 1298 PAPER { 1299 Output_def *p = get_paper (parser); 1300 p->input_origin_ = @$; 1301 parser->lexer_->add_scope (p->scope_); 1302 $$ = p->unprotect (); 1303 } 1304 | MIDI { 1305 Output_def *p = get_midi (parser); 1306 $$ = p->unprotect (); 1307 parser->lexer_->add_scope (p->scope_); 1308 } 1309 | LAYOUT { 1310 Output_def *p = get_layout (parser); 1311 1312 parser->lexer_->add_scope (p->scope_); 1313 $$ = p->unprotect (); 1314 } 1315 ; 1316 1317output_def_head_with_mode_switch: 1318 output_def_head { 1319 parser->lexer_->push_initial_state (); 1320 $$ = $1; 1321 } 1322 ; 1323 1324// We need this weird nonterminal because both music as well as a 1325// context definition can start with \context and the difference is 1326// only apparent after looking at the next token. If it is '{', there 1327// is still time to escape from notes mode. 1328 1329music_or_context_def: 1330 music_assign 1331 | context_def_spec_block 1332 ; 1333 1334output_def_body: 1335 output_def_head_with_mode_switch '{' { 1336 unsmob<Output_def> ($1)->input_origin_.set_spot (@$); 1337 // This is a stupid trick to mark the beginning of the 1338 // body for deciding whether to allow 1339 // embedded_scm_active to have an output definition 1340 $$ = scm_list_1 ($1); 1341 } 1342 | output_def_body assignment { 1343 if (scm_is_pair ($1)) 1344 $$ = scm_car ($1); 1345 } 1346 | output_def_body embedded_scm_active 1347 { 1348 // We don't switch into note mode for Scheme functions 1349 // here. Does not seem warranted/required in output 1350 // definitions. 1351 if (scm_is_pair ($1)) 1352 { 1353 Output_def *o = unsmob<Output_def> ($2); 1354 if (o) { 1355 o->input_origin_.set_spot (@$); 1356 $1 = o->self_scm (); 1357 parser->lexer_->remove_scope (); 1358 parser->lexer_->add_scope (o->scope_); 1359 $2 = SCM_UNSPECIFIED; 1360 } else 1361 $1 = scm_car ($1); 1362 } 1363 if (unsmob<Context_def> ($2)) 1364 assign_context_def (unsmob<Output_def> ($1), $2); 1365 // Seems unlikely, but let's be complete: 1366 else if (unsmob<Music> ($2)) 1367 { 1368 SCM proc = parser->lexer_->lookup_identifier ("output-def-music-handler"); 1369 scm_call_2 (proc, $1, $2); 1370 } else if (!scm_is_eq ($2, SCM_UNSPECIFIED)) 1371 parser->parser_error (@2, _("bad expression type")); 1372 $$ = $1; 1373 } 1374 | output_def_body SCM_TOKEN { 1375 if (scm_is_pair ($1)) 1376 $$ = scm_car ($1); 1377 // Evaluate and ignore #xxx, as opposed to \xxx 1378 parser->lexer_->eval_scm_token ($2, @2); 1379 } 1380 | output_def_body 1381 { 1382 if (scm_is_pair ($1)) 1383 $1 = scm_car ($1); 1384 parser->lexer_->push_note_state (); 1385 } music_or_context_def 1386 { 1387 parser->lexer_->pop_state (); 1388 if (unsmob<Context_def> ($3)) 1389 assign_context_def (unsmob<Output_def> ($1), $3); 1390 else { 1391 1392 SCM proc = parser->lexer_->lookup_identifier ("output-def-music-handler"); 1393 scm_call_2 (proc, $1, $3); 1394 } 1395 $$ = $1; 1396 } 1397 | output_def_body error { 1398 1399 } 1400 ; 1401 1402tempo_event: 1403 TEMPO steno_duration '=' tempo_range { 1404 $$ = MAKE_SYNTAX (tempo, @$, SCM_EOL, $2, $4); 1405 } 1406 | TEMPO text steno_duration '=' tempo_range { 1407 $$ = MAKE_SYNTAX (tempo, @$, $2, $3, $5); 1408 } 1409 | TEMPO text { 1410 $$ = MAKE_SYNTAX (tempo, @$, $2); 1411 } %prec ':' 1412 ; 1413 1414/* 1415The representation of a list is reversed to have efficient append. */ 1416 1417music_list: 1418 /* empty */ { 1419 $$ = SCM_EOL; 1420 } 1421 | music_list music_embedded { 1422 if (unsmob<Music> ($2)) 1423 $$ = scm_cons ($2, $1); 1424 } 1425 | music_list error { 1426 Music *m = MY_MAKE_MUSIC("Music", @$); 1427 // ugh. code dup 1428 set_property (m, "error-found", SCM_BOOL_T); 1429 $$ = scm_cons (m->self_scm (), $1); 1430 m->unprotect (); /* UGH */ 1431 } 1432 ; 1433 1434braced_music_list: 1435 '{' music_list '}' 1436 { 1437 $$ = reverse_music_list (parser, @$, $2, true, false); 1438 } 1439 ; 1440 1441music: music_assign 1442 | lyric_element_music 1443 | pitch_as_music 1444 ; 1445 1446pitch_as_music: 1447 pitch_or_music 1448 { 1449 $$ = make_music_from_simple (parser, @1, $1); 1450 if (!unsmob<Music> ($$)) 1451 { 1452 parser->parser_error (@1, _ ("music expected")); 1453 $$ = MAKE_SYNTAX (void_music, @$); 1454 } 1455 } 1456 ; 1457 1458music_embedded: 1459 music 1460 | post_event 1461 | music_embedded_backup 1462 { 1463 $$ = $1; 1464 } 1465 | music_embedded_backup BACKUP lyric_element_music 1466 { 1467 $$ = $3; 1468 } 1469 | duration post_events %prec ':' 1470 { 1471 Music *n = MY_MAKE_MUSIC ("NoteEvent", @$); 1472 1473 parser->default_duration_ = *unsmob<Duration> ($1); 1474 set_property (n, "duration", $1); 1475 1476 if (scm_is_pair ($2)) 1477 set_property (n, "articulations", 1478 scm_reverse_x ($2, SCM_EOL)); 1479 $$ = n->unprotect (); 1480 } 1481 ; 1482 1483music_embedded_backup: 1484 embedded_scm 1485 { 1486 if (scm_is_eq ($1, SCM_UNSPECIFIED) 1487 || unsmob<Music> ($1)) 1488 $$ = $1; 1489 else if (parser->lexer_->is_lyric_state () 1490 && Text_interface::is_markup ($1)) 1491 MYBACKUP (LYRIC_ELEMENT, $1, @1); 1492 else { 1493 @$.warning (_ ("Ignoring non-music expression")); 1494 $$ = SCM_UNSPECIFIED; 1495 } 1496 } 1497 ; 1498 1499// music_assign does not need to contain lyrics: there are no 1500// assignments in lyricmode. 1501music_assign: 1502 simple_music 1503 | composite_music %prec COMPOSITE 1504 ; 1505 1506repeated_music: 1507 REPEAT simple_string unsigned_number music 1508 { 1509 $$ = MAKE_SYNTAX (repeat, @$, $2, $3, $4); 1510 } 1511 | REPEAT simple_string unsigned_number music sequential_alternative_music 1512 { 1513 $$ = MAKE_SYNTAX (repeat_alt, @$, $2, $3, $4, $5); 1514 } 1515 ; 1516 1517sequential_alternative_music: 1518 ALTERNATIVE braced_music_list { 1519 $$ = MAKE_SYNTAX (sequential_alternative_music, @$, $2); 1520 } 1521 | 1522 ALTERNATIVE MUSIC_IDENTIFIER { $$ = $2; } 1523 ; 1524 1525sequential_music: 1526 sequential_alternative_music { 1527 $$ = $1; 1528 } 1529 | SEQUENTIAL braced_music_list { 1530 $$ = MAKE_SYNTAX (sequential_music, @$, $2); 1531 } 1532 | braced_music_list { 1533 $$ = MAKE_SYNTAX (sequential_music, @$, $1); 1534 } 1535 ; 1536 1537simultaneous_music: 1538 SIMULTANEOUS braced_music_list { 1539 $$ = MAKE_SYNTAX (simultaneous_music, @$, $2); 1540 } 1541 | DOUBLE_ANGLE_OPEN music_list DOUBLE_ANGLE_CLOSE { 1542 $$ = MAKE_SYNTAX (simultaneous_music, @$, 1543 reverse_music_list (parser, @$, $2, 1544 true, false)); 1545 } 1546 ; 1547 1548simple_music: 1549 event_chord 1550 | music_property_def 1551 | context_change 1552 ; 1553 1554context_modification: 1555 WITH 1556 { 1557 parser->lexer_->push_note_state (); 1558 } '{' context_mod_list '}' 1559 { 1560 parser->lexer_->pop_state (); 1561 $$ = $4; 1562 } 1563 | WITH context_modification_arg 1564 { 1565 if (unsmob<Music> ($2)) { 1566 SCM proc = parser->lexer_->lookup_identifier ("context-mod-music-handler"); 1567 $2 = scm_call_1 (proc, $2); 1568 } 1569 if (unsmob<Context_mod> ($2)) 1570 $$ = $2; 1571 else { 1572 // let's permit \with #*unspecified* to go for 1573 // an empty context mod 1574 if (!scm_is_eq ($2, SCM_UNSPECIFIED)) 1575 parser->parser_error (@2, _ ("not a context mod")); 1576 $$ = Context_mod ().smobbed_copy (); 1577 } 1578 } 1579 ; 1580 1581context_modification_arg: 1582 embedded_scm 1583 | MUSIC_IDENTIFIER 1584 ; 1585 1586/* A list of single mods collected from a (possibly empty) sequence of 1587 * context modifications, usually written as \with ... \with ... 1588 */ 1589 1590optional_context_mods: 1591 context_modification_mods_list 1592 { 1593 if (scm_is_pair ($1)) 1594 $$ = scm_append_x (scm_reverse_x ($1, SCM_EOL)); 1595 } 1596 ; 1597 1598/* The worker for optional_context_mods conses a (reversed) list where 1599 * each element contains the list of single context mods from one 1600 * context modification block. Context_mod::get_mods creates fresh 1601 * copies, so it's okay to use append! on them. 1602 */ 1603 1604context_modification_mods_list: 1605 /**/ { 1606 $$ = SCM_EOL; 1607 } 1608 | context_modification_mods_list context_modification 1609 { 1610 if (Context_mod *m = unsmob<Context_mod> ($2)) 1611 $$ = scm_cons (m->get_mods (), $1); 1612 } 1613 ; 1614 1615/* A Context_mod is a container for a list of context mods like 1616 * \consists ... \override ... . context_mod_list produces a 1617 * Context_mod from the inside of a \with { ... } statement. 1618 */ 1619 1620context_mod_list: 1621 /**/ { 1622 $$ = Context_mod ().smobbed_copy (); 1623 } 1624 | context_mod_list context_mod { 1625 if (!SCM_UNBNDP ($2)) 1626 unsmob<Context_mod> ($1)->add_context_mod ($2); 1627 } 1628 | context_mod_list context_mod_arg { 1629 if (unsmob<Music> ($2)) { 1630 SCM proc = parser->lexer_->lookup_identifier ("context-mod-music-handler"); 1631 $2 = scm_call_1 (proc, $2); 1632 } 1633 if (unsmob<Context_mod> ($2)) 1634 unsmob<Context_mod> ($$)->add_context_mods 1635 (unsmob<Context_mod> ($2)->get_mods ()); 1636 else if (!scm_is_eq ($2, SCM_UNSPECIFIED)) 1637 parser->parser_error (@2, _ ("not a context mod")); 1638 } 1639 ; 1640 1641context_prefix: 1642 CONTEXT symbol optional_id optional_context_mods { 1643 $$ = START_MAKE_SYNTAX (context_find_or_create, $2, $3, $4); 1644 } 1645 | NEWCONTEXT symbol optional_id optional_context_mods { 1646 $$ = START_MAKE_SYNTAX (context_create, $2, $3, $4); 1647 } 1648 ; 1649 1650new_lyrics: 1651 ADDLYRICS optional_context_mods lyric_mode_music { 1652 $$ = scm_acons ($3, $2, SCM_EOL); 1653 } 1654 | new_lyrics ADDLYRICS optional_context_mods lyric_mode_music { 1655 $$ = scm_acons ($4, $3, $1); 1656 } 1657 ; 1658 1659/* basic_music is basically the same as composite_music but with 1660 * context-prefixed music and lyricized music explicitly removed. The 1661 * reason is that in a sequence 1662 * 1663 * \new Staff \new Voice { ... } \addlyrics { ... } \addlyrics { ... } 1664 * 1665 * we need to group both \addlyrics together (as they go with the same 1666 * voice) but then combine them with \new Voice { ... }, meaning that 1667 * combining \new Voice { ... } needs higher priority than 1668 * { ... } \addlyrics, and *not* have \new Staff \new Voice { ... } 1669 * combine before combining \new Voice { ... } \addlyrics: only one 1670 * layer of context-prefixed music should assemble before \addlyrics 1671 * is integrated. Total mess, and we sort this mess out with explicit 1672 * rules preferring a single context-prefix. 1673 */ 1674 1675basic_music: 1676 music_function_call 1677 | repeated_music 1678 | music_bare 1679 | LYRICSTO simple_string lyric_mode_music { 1680 $$ = MAKE_SYNTAX (lyric_combine, @$, $2, SCM_EOL, $3); 1681 } 1682 | LYRICSTO symbol '=' simple_string lyric_mode_music 1683 { 1684 $$ = MAKE_SYNTAX (lyric_combine, @$, $4, $2, $5); 1685 } 1686 ; 1687 1688contextable_music: 1689 basic_music 1690 | pitch_as_music 1691 | event_chord 1692 ; 1693 1694contexted_basic_music: 1695 context_prefix contextable_music new_lyrics 1696 { 1697 Input i; 1698 i.set_location (@1, @2); 1699 $$ = FINISH_MAKE_SYNTAX ($1, i, $2); 1700 $$ = MAKE_SYNTAX (add_lyrics, @$, $$, scm_reverse_x ($3, SCM_EOL)); 1701 } %prec COMPOSITE 1702 | context_prefix contextable_music 1703 { 1704 $$ = FINISH_MAKE_SYNTAX ($1, @$, $2); 1705 } %prec COMPOSITE 1706 | context_prefix contexted_basic_music 1707 { 1708 $$ = FINISH_MAKE_SYNTAX ($1, @$, $2); 1709 } 1710 ; 1711 1712composite_music: 1713 basic_music %prec COMPOSITE 1714 | contexted_basic_music 1715 | basic_music new_lyrics 1716 { 1717 $$ = MAKE_SYNTAX (add_lyrics, @$, $1, scm_reverse_x ($2, SCM_EOL)); 1718 } %prec COMPOSITE 1719 ; 1720 1721music_bare: 1722 mode_changed_music 1723 | MUSIC_IDENTIFIER 1724 | grouped_music_list 1725 ; 1726 1727grouped_music_list: 1728 simultaneous_music { $$ = $1; } 1729 | sequential_music { $$ = $1; } 1730 ; 1731 1732/* Function argument lists are arguably the most complex part in the 1733 * parser. They are pretty tricky to understand because of the way 1734 * they are processed, and because of optional arguments that can be 1735 * omitted. When there are several optional arguments in a row, 1736 * omitting one automatically omits all following arguments. Optional 1737 * arguments can only be omitted when either 1738 * 1739 * a) the omission is explicitly started with \default 1740 * b) the omission is implicitly started by an argument not matching 1741 * its predicate, and there is a mandatory argument later that can 1742 * "catch" the argument that does not fit. 1743 * 1744 * When argument parsing starts, the lexer pushes EXPECT_SCM tokens 1745 * (corresponding to mandatory arguments and having a predicate 1746 * function as semantic value) or EXPECT_OPTIONAL EXPECT_SCM (where 1747 * the semantic value of the EXPECT_OPTIONAL token is the default to 1748 * use when the optional argument is omitted, and EXPECT_SCM again has 1749 * the argument predicate as semantic value) in reverse order to the 1750 * parser, followed by EXPECT_NO_MORE_ARGS. The argument list is then 1751 * processed inside-out while actual tokens are consumed. 1752 * 1753 * This means that the argument list tokens determine the actions 1754 * taken as they arrive. The structure of the argument list is known 1755 * to the parser and stored in its parse stack when the first argument 1756 * is being parsed. What the parser does not know is which predicates 1757 * will match and whether or not \default will be appearing in the 1758 * argument list, and where. 1759 * 1760 * Sequences of 0 or more optional arguments are scanned using either 1761 * function_arglist_backup or function_arglist_nonbackup. The first 1762 * is used when optional arguments are followed by at least one 1763 * mandatory argument: in that case optional arguments may be skipped 1764 * by either a false predicate (in which case the expression will be 1765 * pushed back as one or more tokens, preceded by a BACKUP token) or 1766 * by using \default. 1767 * 1768 * If optional arguments are at the end of the argument list, they are 1769 * instead scanned using function_arglist_nonbackup: here the only 1770 * manner to enter into skipping of optional arguments is the use of 1771 * \default. 1772 * 1773 * The argument list of a normal function call is parsed using 1774 * function_arglist. The part of an argument list before a mandatory 1775 * argument is parsed using function_arglist_optional. 1776 * 1777 * The difference is that leading optional arguments are scanned using 1778 * function_arglist_nonbackup and function_arglist_backup, 1779 * respectively. 1780 * 1781 * Most other details are obvious in the rules themselves. 1782 * 1783 */ 1784 1785symbol_list_arg: 1786 SYMBOL_LIST 1787 | SYMBOL_LIST '.' symbol_list_rev 1788 { 1789 $$ = scm_append (scm_list_2 ($1, scm_reverse_x ($3, SCM_EOL))); 1790 } 1791 | SYMBOL_LIST ',' symbol_list_rev 1792 { 1793 $$ = scm_append (scm_list_2 ($1, scm_reverse_x ($3, SCM_EOL))); 1794 } 1795 ; 1796 1797symbol_list_rev: 1798 symbol_list_part 1799 | symbol_list_rev '.' symbol_list_part 1800 { 1801 $$ = scm_append_x (scm_list_2 ($3, $1)); 1802 } 1803 | symbol_list_rev ',' symbol_list_part 1804 { 1805 $$ = scm_append_x (scm_list_2 ($3, $1)); 1806 } 1807 ; 1808 1809// symbol_list_part delivers elements in reverse copy, no lookahead 1810 1811symbol_list_part: 1812 symbol_list_part_bare 1813 | embedded_scm_bare 1814 { 1815 $$ = make_reverse_key_list ($1); 1816 if (SCM_UNBNDP ($$)) { 1817 parser->parser_error (@1, _("not a key")); 1818 $$ = SCM_EOL; 1819 } 1820 } 1821 ; 1822 1823 1824symbol_list_element: 1825 STRING 1826 { 1827 $$ = scm_string_to_symbol ($1); 1828 } 1829 | UNSIGNED 1830 ; 1831 1832 1833symbol_list_part_bare: 1834 SYMBOL 1835 { 1836 $$ = try_word_variants (Lily::key_list_p, $1); 1837 if (SCM_UNBNDP ($$)) { 1838 parser->parser_error (@1, _("not a key")); 1839 $$ = SCM_EOL; 1840 } else 1841 $$ = scm_reverse ($$); 1842 } 1843 | symbol_list_element 1844 { 1845 $$ = scm_list_1 ($1); 1846 } 1847 ; 1848 1849function_arglist_nonbackup: 1850 function_arglist_common 1851 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup post_event_nofinger 1852 { 1853 $$ = check_scheme_arg (parser, @4, $4, $3, $2); 1854 } 1855 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup '-' UNSIGNED 1856 { 1857 SCM n = scm_difference ($5, SCM_UNDEFINED); 1858 if (scm_is_true (scm_call_1 ($2, n))) 1859 $$ = scm_cons (n, $3); 1860 else { 1861 Music *t = MY_MAKE_MUSIC ("FingeringEvent", @5); 1862 set_property (t, "digit", $5); 1863 $$ = check_scheme_arg (parser, @4, t->unprotect (), 1864 $3, $2, n); 1865 } 1866 } 1867 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup '-' REAL 1868 { 1869 $$ = check_scheme_arg (parser, @4, 1870 scm_difference ($5, SCM_UNDEFINED), 1871 $3, $2); 1872 } 1873 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup '-' NUMBER_IDENTIFIER 1874 { 1875 $$ = check_scheme_arg (parser, @4, 1876 scm_difference ($5, SCM_UNDEFINED), 1877 $3, $2); 1878 } 1879 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup embedded_scm_arg 1880 { 1881 if (scm_is_true (scm_call_1 ($2, $4))) 1882 $$ = scm_cons ($4, $3); 1883 else 1884 $$ = check_scheme_arg (parser, @4, 1885 make_music_from_simple 1886 (parser, @4, $4), 1887 $3, $2, $4); 1888 } 1889 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup bare_number_common 1890 { 1891 $$ = check_scheme_arg (parser, @4, $4, $3, $2); 1892 } 1893 | function_arglist_nonbackup_reparse REPARSE pitch_or_music 1894 { 1895 if (scm_is_true (scm_call_1 ($2, $3))) 1896 $$ = scm_cons ($3, $1); 1897 else 1898 $$ = check_scheme_arg (parser, @3, 1899 make_music_from_simple 1900 (parser, @3, $3), 1901 $1, $2, $3); 1902 } 1903 | function_arglist_nonbackup_reparse REPARSE duration 1904 { 1905 $$ = check_scheme_arg (parser, @3, $3, $1, $2); 1906 } 1907 | function_arglist_nonbackup_reparse REPARSE reparsed_rhythm 1908 { 1909 $$ = check_scheme_arg (parser, @3, $3, $1, $2); 1910 } 1911 | function_arglist_nonbackup_reparse REPARSE bare_number_common 1912 { 1913 $$ = check_scheme_arg (parser, @3, $3, $1, $2); 1914 } 1915 | function_arglist_nonbackup_reparse REPARSE SCM_ARG 1916 { 1917 $$ = check_scheme_arg (parser, @3, $3, $1, $2); 1918 } 1919 | function_arglist_nonbackup_reparse REPARSE lyric_element_music 1920 { 1921 $$ = check_scheme_arg (parser, @3, $3, $1, $2); 1922 } 1923 | function_arglist_nonbackup_reparse REPARSE symbol_list_arg 1924 { 1925 $$ = check_scheme_arg (parser, @3, $3, $1, $2); 1926 } 1927 ; 1928 1929 1930reparsed_rhythm: 1931 DURATION_ARG dots multipliers post_events 1932 { 1933 SCM d = make_duration ($1, scm_to_int ($2), $3); 1934 parser->default_duration_ = *unsmob<Duration> (d); 1935 $$ = make_music_from_simple (parser, @$, d); 1936 Music *m = unsmob<Music> ($$); 1937 assert (m); 1938 if (scm_is_pair ($4)) 1939 set_property (m, "articulations", 1940 scm_reverse_x ($4, SCM_EOL)); 1941 } %prec ':' 1942 ; 1943 1944function_arglist_nonbackup_reparse: 1945 EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup SCM_IDENTIFIER 1946 { 1947 $$ = $3; 1948 SCM res = try_string_variants ($2, $4); 1949 if (!SCM_UNBNDP (res)) 1950 if (scm_is_pair (res)) 1951 MYREPARSE (@4, $2, SYMBOL_LIST, res); 1952 else 1953 MYREPARSE (@4, $2, SCM_ARG, res); 1954 else if (scm_is_true 1955 (scm_call_1 1956 ($2, make_music_from_simple 1957 (parser, @4, $4)))) 1958 MYREPARSE (@4, $2, STRING, $4); 1959 else 1960 MYREPARSE (@4, $2, SCM_ARG, $4); 1961 } 1962 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup pitch 1963 { 1964 $$ = $3; 1965 if (scm_is_true 1966 (scm_call_1 1967 ($2, make_music_from_simple 1968 (parser, @4, $4)))) 1969 MYREPARSE (@4, $2, PITCH_IDENTIFIER, $4); 1970 else 1971 MYREPARSE (@4, $2, SCM_ARG, $4); 1972 } 1973 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup steno_tonic_pitch 1974 { 1975 $$ = $3; 1976 if (scm_is_true 1977 (scm_call_1 1978 ($2, make_music_from_simple 1979 (parser, @4, $4)))) 1980 MYREPARSE (@4, $2, TONICNAME_PITCH, $4); 1981 else 1982 MYREPARSE (@4, $2, SCM_ARG, $4); 1983 } 1984 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup STRING 1985 { 1986 $$ = $3; 1987 SCM res = try_string_variants ($2, $4); 1988 if (!SCM_UNBNDP (res)) 1989 if (scm_is_pair (res)) 1990 MYREPARSE (@4, $2, SYMBOL_LIST, res); 1991 else 1992 MYREPARSE (@4, $2, SCM_ARG, res); 1993 else if (scm_is_true 1994 (scm_call_1 1995 ($2, make_music_from_simple 1996 (parser, @4, $4)))) 1997 MYREPARSE (@4, $2, STRING, $4); 1998 else 1999 MYREPARSE (@4, $2, SCM_ARG, $4); 2000 } 2001 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup SYMBOL 2002 { 2003 $$ = $3; 2004 SCM res = try_word_variants ($2, $4); 2005 if (!SCM_UNBNDP (res)) 2006 if (scm_is_pair (res)) 2007 MYREPARSE (@4, $2, SYMBOL_LIST, res); 2008 else 2009 MYREPARSE (@4, $2, SCM_ARG, res); 2010 else if (scm_is_true 2011 (scm_call_1 2012 ($2, make_music_from_simple 2013 (parser, @4, $4)))) 2014 MYREPARSE (@4, $2, STRING, $4); 2015 else 2016 MYREPARSE (@4, $2, SCM_ARG, $4); 2017 } 2018 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup full_markup 2019 { 2020 $$ = $3; 2021 if (scm_is_true (scm_call_1 ($2, $4))) 2022 MYREPARSE (@4, $2, SCM_ARG, $4); 2023 else if (scm_is_true 2024 (scm_call_1 2025 ($2, make_music_from_simple 2026 (parser, @4, $4)))) 2027 MYREPARSE (@4, $2, STRING, $4); 2028 else 2029 MYREPARSE (@4, $2, SCM_ARG, $4); 2030 } 2031 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup UNSIGNED 2032 { 2033 $$ = $3; 2034 if (scm_is_true (scm_call_1 ($2, $4))) 2035 // May be 3 \cm or similar 2036 MYREPARSE (@4, $2, REAL, $4); 2037 else if (scm_is_true (scm_call_1 ($2, scm_list_1 ($4)))) 2038 MYREPARSE (@4, $2, SYMBOL_LIST, scm_list_1 ($4)); 2039 else { 2040 SCM d = make_duration ($4); 2041 if (!SCM_UNBNDP (d)) { 2042 if (scm_is_true (scm_call_1 ($2, d))) 2043 MYREPARSE (@4, $2, DURATION_IDENTIFIER, d); 2044 else if (scm_is_true 2045 (scm_call_1 2046 ($2, make_music_from_simple (parser, @4, d)))) 2047 MYREPARSE (@4, $2, DURATION_ARG, d); 2048 else 2049 MYREPARSE (@4, $2, SCM_ARG, $4); // trigger error 2050 } else 2051 MYREPARSE (@4, $2, SCM_ARG, $4); // trigger error 2052 } 2053 } 2054 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup DURATION_IDENTIFIER 2055 { 2056 $$ = $3; 2057 if (scm_is_true (scm_call_1 ($2, $4))) 2058 MYREPARSE (@4, $2, DURATION_IDENTIFIER, $4); 2059 else if (scm_is_true 2060 (scm_call_1 2061 ($2, make_music_from_simple (parser, @4, $4)))) 2062 MYREPARSE (@4, $2, DURATION_ARG, $4); 2063 else 2064 MYREPARSE (@4, $2, SCM_ARG, $4); // trigger error 2065 } 2066 ; 2067 2068 2069// function_arglist_backup can't occur at the end of an argument 2070// list. 2071function_arglist_backup: 2072 function_arglist_common 2073 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup embedded_scm_arg 2074 { 2075 if (scm_is_true (scm_call_1 ($2, $4))) 2076 $$ = scm_cons ($4, $3); 2077 else { 2078 $$ = make_music_from_simple (parser, @4, $4); 2079 if (scm_is_true (scm_call_1 ($2, $$))) 2080 $$ = scm_cons ($$, $3); 2081 else 2082 { 2083 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2084 MYBACKUP (SCM_ARG, $4, @4); 2085 } 2086 } 2087 } 2088 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup post_event_nofinger 2089 { 2090 if (scm_is_true (scm_call_1 ($2, $4))) 2091 { 2092 $$ = scm_cons ($4, $3); 2093 } else { 2094 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2095 MYBACKUP (EVENT_IDENTIFIER, $4, @4); 2096 } 2097 } 2098 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup pitch 2099 { 2100 if (scm_is_true 2101 (scm_call_1 2102 ($2, make_music_from_simple 2103 (parser, @4, $4)))) 2104 { 2105 $$ = $3; 2106 MYREPARSE (@4, $2, PITCH_IDENTIFIER, $4); 2107 } else if (scm_is_true (scm_call_1 ($2, $4))) 2108 $$ = scm_cons ($4, $3); 2109 else { 2110 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2111 MYBACKUP (PITCH_IDENTIFIER, $4, @4); 2112 } 2113 } 2114 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup steno_tonic_pitch 2115 { 2116 if (scm_is_true 2117 (scm_call_1 2118 ($2, make_music_from_simple 2119 (parser, @4, $4)))) 2120 { 2121 $$ = $3; 2122 MYREPARSE (@4, $2, TONICNAME_PITCH, $4); 2123 } else if (scm_is_true (scm_call_1 ($2, $4))) 2124 $$ = scm_cons ($4, $3); 2125 else { 2126 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2127 MYBACKUP (TONICNAME_PITCH, $4, @4); 2128 } 2129 } 2130 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup full_markup 2131 { 2132 if (scm_is_true (scm_call_1 ($2, $4))) 2133 $$ = scm_cons ($4, $3); 2134 else { 2135 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2136 MYBACKUP (SCM_IDENTIFIER, $4, @4); 2137 } 2138 } 2139 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup UNSIGNED 2140 { 2141 $$ = $3; 2142 if (scm_is_true (scm_call_1 ($2, $4))) 2143 // May be 3 \cm or similar 2144 MYREPARSE (@4, $2, REAL, $4); 2145 else if (scm_is_true (scm_call_1 ($2, scm_list_1 ($4)))) 2146 MYREPARSE (@4, $2, SYMBOL_LIST, scm_list_1 ($4)); 2147 else { 2148 SCM d = make_duration ($4); 2149 if (!SCM_UNBNDP (d)) { 2150 if (scm_is_true (scm_call_1 ($2, d))) 2151 MYREPARSE (@4, $2, DURATION_IDENTIFIER, d); 2152 else if (scm_is_true 2153 (scm_call_1 2154 ($2, make_music_from_simple (parser, @4, d)))) 2155 MYREPARSE (@4, $2, DURATION_ARG, d); 2156 else { 2157 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2158 MYBACKUP (UNSIGNED, $4, @4); 2159 } 2160 } else { 2161 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2162 MYBACKUP (UNSIGNED, $4, @4); 2163 } 2164 } 2165 } 2166 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup REAL 2167 { 2168 if (scm_is_true (scm_call_1 ($2, $4))) 2169 { 2170 $$ = $3; 2171 MYREPARSE (@4, $2, REAL, $4); 2172 } else { 2173 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2174 MYBACKUP (REAL, $4, @4); 2175 } 2176 } 2177 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup NUMBER_IDENTIFIER 2178 { 2179 if (scm_is_true (scm_call_1 ($2, $4))) 2180 { 2181 $$ = scm_cons ($4, $3); 2182 } else { 2183 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2184 MYBACKUP (NUMBER_IDENTIFIER, $4, @4); 2185 } 2186 } 2187 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup '-' UNSIGNED 2188 { 2189 SCM n = scm_difference ($5, SCM_UNDEFINED); 2190 if (scm_is_true (scm_call_1 ($2, n))) { 2191 $$ = $3; 2192 MYREPARSE (@5, $2, REAL, n); 2193 } else { 2194 Music *t = MY_MAKE_MUSIC ("FingeringEvent", @5); 2195 set_property (t, "digit", $5); 2196 $$ = t->unprotect (); 2197 if (scm_is_true (scm_call_1 ($2, $$))) 2198 $$ = scm_cons ($$, $3); 2199 else { 2200 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2201 MYBACKUP (UNSIGNED, $5, @5); 2202 parser->lexer_->push_extra_token (@4, '-'); 2203 } 2204 } 2205 } 2206 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup '-' REAL 2207 { 2208 SCM n = scm_difference ($5, SCM_UNDEFINED); 2209 if (scm_is_true (scm_call_1 ($2, n))) { 2210 MYREPARSE (@5, $2, REAL, n); 2211 $$ = $3; 2212 } else { 2213 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2214 MYBACKUP (REAL, n, @5); 2215 } 2216 } 2217 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup '-' NUMBER_IDENTIFIER 2218 { 2219 SCM n = scm_difference ($5, SCM_UNDEFINED); 2220 if (scm_is_true (scm_call_1 ($2, n))) { 2221 $$ = scm_cons (n, $3); 2222 } else { 2223 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2224 MYBACKUP (NUMBER_IDENTIFIER, n, @5); 2225 } 2226 } 2227 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup DURATION_IDENTIFIER 2228 { 2229 $$ = $3; 2230 if (scm_is_true (scm_call_1 ($2, $4))) 2231 MYREPARSE (@4, $2, DURATION_IDENTIFIER, $4); 2232 else if (scm_is_true 2233 (scm_call_1 2234 ($2, make_music_from_simple (parser, @4, $4)))) 2235 MYREPARSE (@4, $2, DURATION_ARG, $4); 2236 else { 2237 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2238 MYBACKUP (DURATION_IDENTIFIER, $4, @4); 2239 } 2240 } 2241 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup SCM_IDENTIFIER 2242 { 2243 SCM res = try_string_variants ($2, $4); 2244 if (!SCM_UNBNDP (res)) 2245 if (scm_is_pair (res)) { 2246 $$ = $3; 2247 MYREPARSE (@4, $2, SYMBOL_LIST, res); 2248 } 2249 else 2250 $$ = scm_cons (res, $3); 2251 else { 2252 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2253 MYBACKUP (SCM_IDENTIFIER, $4, @4); 2254 } 2255 } 2256 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup STRING 2257 { 2258 SCM res = try_string_variants ($2, $4); 2259 if (!SCM_UNBNDP (res)) 2260 if (scm_is_pair (res)) { 2261 $$ = $3; 2262 MYREPARSE (@4, $2, SYMBOL_LIST, res); 2263 } 2264 else 2265 $$ = scm_cons (res, $3); 2266 else { 2267 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2268 MYBACKUP (STRING, $4, @4); 2269 } 2270 } 2271 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup SYMBOL 2272 { 2273 SCM res = try_word_variants ($2, $4); 2274 if (!SCM_UNBNDP (res)) 2275 if (scm_is_pair (res)) { 2276 $$ = $3; 2277 MYREPARSE (@4, $2, SYMBOL_LIST, res); 2278 } 2279 else 2280 $$ = scm_cons (res, $3); 2281 else { 2282 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2283 MYBACKUP (STRING, $4, @4); 2284 } 2285 } 2286 | function_arglist_backup REPARSE pitch_or_music 2287 { 2288 if (scm_is_true (scm_call_1 ($2, $3))) 2289 $$ = scm_cons ($3, $1); 2290 else 2291 $$ = check_scheme_arg (parser, @3, 2292 make_music_from_simple 2293 (parser, @3, $3), 2294 $1, $2); 2295 } 2296 | function_arglist_backup REPARSE bare_number_common 2297 { 2298 $$ = check_scheme_arg (parser, @3, 2299 $3, $1, $2); 2300 } 2301 | function_arglist_backup REPARSE duration 2302 { 2303 $$ = check_scheme_arg (parser, @3, 2304 $3, $1, $2); 2305 } 2306 | function_arglist_backup REPARSE reparsed_rhythm 2307 { 2308 $$ = check_scheme_arg (parser, @3, 2309 $3, $1, $2); 2310 } 2311 | function_arglist_backup REPARSE symbol_list_arg 2312 { 2313 $$ = check_scheme_arg (parser, @3, $3, $1, $2); 2314 } 2315 ; 2316 2317function_arglist: 2318 function_arglist_nonbackup 2319 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_skip_nonbackup DEFAULT 2320 { 2321 $$ = scm_cons (loc_on_copy (parser, @4, $1), $3); 2322 } 2323 ; 2324 2325function_arglist_skip_nonbackup: 2326 function_arglist_nonbackup 2327 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_skip_nonbackup 2328 { 2329 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2330 } 2331 ; 2332 2333// Partial function arglists are returned just in their incomplete 2334// state: when combined with the music function, the missing parts of 2335// the signature can be reconstructed 2336// 2337// To serve as a partial arglist, the argument list must absolutely 2338// _not_ be in "skipping optional arguments" mode since then there is 2339// some backup token that has nowhere to go before \etc. 2340// 2341// So we can skim off an arbitrary number of arguments from the end of 2342// the argument list. The argument list remaining afterwards has to 2343// be in not-skipping-optional-arguments mode. 2344 2345function_arglist_partial: 2346 EXPECT_SCM function_arglist_optional 2347 { 2348 $$ = $2; 2349 } 2350 | EXPECT_SCM function_arglist_partial_optional 2351 { 2352 $$ = $2; 2353 } 2354 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup 2355 { 2356 $$ = $3; 2357 } 2358 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_partial 2359 { 2360 $$ = $3; 2361 } 2362 ; 2363 2364function_arglist_partial_optional: 2365 EXPECT_SCM function_arglist_optional 2366 { 2367 $$ = $2; 2368 } 2369 | EXPECT_SCM function_arglist_partial_optional 2370 { 2371 $$ = $2; 2372 } 2373 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup 2374 { 2375 $$ = $3; 2376 } 2377 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_partial_optional 2378 { 2379 $$ = $3; 2380 } 2381 ; 2382 2383function_arglist_common: 2384 EXPECT_NO_MORE_ARGS { 2385 $$ = SCM_EOL; 2386 } 2387 | EXPECT_SCM function_arglist_optional embedded_scm_arg 2388 { 2389 if (scm_is_true (scm_call_1 ($1, $3))) 2390 $$ = scm_cons ($3, $2); 2391 else 2392 $$ = check_scheme_arg (parser, @3, 2393 make_music_from_simple 2394 (parser, @3, $3), 2395 $2, $1, $3); 2396 } 2397 | EXPECT_SCM function_arglist_optional bare_number_common 2398 { 2399 $$ = check_scheme_arg (parser, @3, 2400 $3, $2, $1); 2401 } 2402 | EXPECT_SCM function_arglist_optional post_event_nofinger 2403 { 2404 $$ = check_scheme_arg (parser, @3, 2405 $3, $2, $1); 2406 } 2407 | EXPECT_SCM function_arglist_optional '-' NUMBER_IDENTIFIER 2408 { 2409 SCM n = scm_difference ($4, SCM_UNDEFINED); 2410 $$ = check_scheme_arg (parser, @4, n, $2, $1); 2411 } 2412 | function_arglist_common_reparse REPARSE SCM_ARG 2413 { 2414 $$ = check_scheme_arg (parser, @3, 2415 $3, $1, $2); 2416 } 2417 | function_arglist_common_reparse REPARSE lyric_element_music 2418 { 2419 $$ = check_scheme_arg (parser, @3, 2420 $3, $1, $2); 2421 } 2422 | function_arglist_common_reparse REPARSE pitch_or_music 2423 { 2424 if (scm_is_true (scm_call_1 ($2, $3))) 2425 $$ = scm_cons ($3, $1); 2426 else 2427 $$ = check_scheme_arg (parser, @3, 2428 make_music_from_simple 2429 (parser, @3, $3), 2430 $1, $2, $3); 2431 } 2432 | function_arglist_common_reparse REPARSE bare_number_common 2433 { 2434 $$ = check_scheme_arg (parser, @3, 2435 $3, $1, $2); 2436 } 2437 | function_arglist_common_reparse REPARSE duration 2438 { 2439 $$ = check_scheme_arg (parser, @3, 2440 $3, $1, $2); 2441 } 2442 | function_arglist_common_reparse REPARSE reparsed_rhythm 2443 { 2444 $$ = check_scheme_arg (parser, @3, 2445 $3, $1, $2); 2446 } 2447 | function_arglist_common_reparse REPARSE symbol_list_arg 2448 { 2449 $$ = check_scheme_arg (parser, @3, $3, $1, $2); 2450 } 2451 ; 2452 2453function_arglist_common_reparse: 2454 EXPECT_SCM function_arglist_optional SCM_IDENTIFIER 2455 { 2456 $$ = $2; 2457 SCM res = try_string_variants ($1, $3); 2458 if (!SCM_UNBNDP (res)) 2459 if (scm_is_pair (res)) 2460 MYREPARSE (@3, $1, SYMBOL_LIST, res); 2461 else 2462 MYREPARSE (@3, $1, SCM_ARG, res); 2463 else if (scm_is_true 2464 (scm_call_1 2465 ($1, make_music_from_simple (parser, @3, $3)))) 2466 MYREPARSE (@3, $1, LYRIC_ELEMENT, $3); 2467 else 2468 // This is going to flag a syntax error, we 2469 // know the predicate to be false. 2470 MYREPARSE (@3, $1, SCM_ARG, $3); 2471 } 2472 | EXPECT_SCM function_arglist_optional pitch 2473 { 2474 $$ = $2; 2475 if (scm_is_true 2476 (scm_call_1 2477 ($1, make_music_from_simple 2478 (parser, @3, $3)))) 2479 MYREPARSE (@3, $1, PITCH_IDENTIFIER, $3); 2480 else 2481 MYREPARSE (@3, $1, SCM_ARG, $3); 2482 } 2483 | EXPECT_SCM function_arglist_optional steno_tonic_pitch 2484 { 2485 $$ = $2; 2486 if (scm_is_true 2487 (scm_call_1 2488 ($1, make_music_from_simple 2489 (parser, @3, $3)))) 2490 MYREPARSE (@3, $1, TONICNAME_PITCH, $3); 2491 else 2492 MYREPARSE (@3, $1, SCM_ARG, $3); 2493 } 2494 | EXPECT_SCM function_arglist_optional STRING 2495 { 2496 $$ = $2; 2497 SCM res = try_string_variants ($1, $3); 2498 if (!SCM_UNBNDP (res)) 2499 if (scm_is_pair (res)) 2500 MYREPARSE (@3, $1, SYMBOL_LIST, res); 2501 else 2502 MYREPARSE (@3, $1, SCM_ARG, res); 2503 else if (scm_is_true 2504 (scm_call_1 2505 ($1, make_music_from_simple (parser, @3, $3)))) 2506 MYREPARSE (@3, $1, LYRIC_ELEMENT, $3); 2507 else 2508 // This is going to flag a syntax error, we 2509 // know the predicate to be false. 2510 MYREPARSE (@3, $1, SCM_ARG, $3); 2511 } 2512 | EXPECT_SCM function_arglist_optional SYMBOL 2513 { 2514 $$ = $2; 2515 SCM res = try_word_variants ($1, $3); 2516 if (!SCM_UNBNDP (res)) 2517 if (scm_is_pair (res)) 2518 MYREPARSE (@3, $1, SYMBOL_LIST, res); 2519 else 2520 MYREPARSE (@3, $1, SCM_ARG, res); 2521 else if (scm_is_true 2522 (scm_call_1 2523 ($1, make_music_from_simple (parser, @3, $3)))) 2524 MYREPARSE (@3, $1, LYRIC_ELEMENT, $3); 2525 else 2526 // This is going to flag a syntax error, we 2527 // know the predicate to be false. 2528 MYREPARSE (@3, $1, SCM_ARG, $3); 2529 } 2530 | EXPECT_SCM function_arglist_optional full_markup 2531 { 2532 $$ = $2; 2533 if (scm_is_true (scm_call_1 ($1, $3))) 2534 MYREPARSE (@3, $1, SCM_ARG, $3); 2535 else if (scm_is_true 2536 (scm_call_1 2537 ($1, make_music_from_simple (parser, @3, $3)))) 2538 MYREPARSE (@3, $1, LYRIC_ELEMENT, $3); 2539 else 2540 // This is going to flag a syntax error, we 2541 // know the predicate to be false. 2542 MYREPARSE (@3, $1, SCM_ARG, $3); 2543 } 2544 | EXPECT_SCM function_arglist_optional UNSIGNED 2545 { 2546 $$ = $2; 2547 if (scm_is_true (scm_call_1 ($1, $3))) 2548 // May be 3 \cm or similar 2549 MYREPARSE (@3, $1, REAL, $3); 2550 else if (scm_is_true (scm_call_1 ($1, scm_list_1 ($3)))) 2551 MYREPARSE (@3, $1, SYMBOL_LIST, scm_list_1 ($3)); 2552 else { 2553 SCM d = make_duration ($3); 2554 if (!SCM_UNBNDP (d)) { 2555 if (scm_is_true (scm_call_1 ($1, d))) 2556 MYREPARSE (@3, $1, DURATION_IDENTIFIER, d); 2557 else if (scm_is_true 2558 (scm_call_1 2559 ($1, make_music_from_simple (parser, @3, d)))) 2560 MYREPARSE (@3, $1, DURATION_ARG, d); 2561 else 2562 MYREPARSE (@3, $1, SCM_ARG, $3); // trigger error 2563 } else 2564 MYREPARSE (@3, $1, SCM_ARG, $3); // trigger error 2565 } 2566 } 2567 | EXPECT_SCM function_arglist_optional DURATION_IDENTIFIER 2568 { 2569 $$ = $2; 2570 if (scm_is_true (scm_call_1 ($1, $3))) 2571 MYREPARSE (@3, $1, DURATION_IDENTIFIER, $3); 2572 else if (scm_is_true 2573 (scm_call_1 2574 ($1, make_music_from_simple (parser, @3, $3)))) 2575 MYREPARSE (@3, $1, DURATION_ARG, $3); 2576 else 2577 MYREPARSE (@3, $1, SCM_ARG, $3); // trigger error 2578 } 2579 | EXPECT_SCM function_arglist_optional '-' UNSIGNED 2580 { 2581 $$ = $2; 2582 SCM n = scm_difference ($4, SCM_UNDEFINED); 2583 if (scm_is_true (scm_call_1 ($1, n))) 2584 MYREPARSE (@4, $1, REAL, n); 2585 else { 2586 Music *t = MY_MAKE_MUSIC ("FingeringEvent", @4); 2587 set_property (t, "digit", $4); 2588 SCM m = t->unprotect (); 2589 if (scm_is_true (scm_call_1 ($1, m))) 2590 MYREPARSE (@4, $1, SCM_ARG, m); 2591 else 2592 MYREPARSE (@4, $1, SCM_ARG, $4); 2593 } 2594 } 2595 | EXPECT_SCM function_arglist_optional '-' REAL 2596 { 2597 $$ = $2; 2598 SCM n = scm_difference ($4, SCM_UNDEFINED); 2599 MYREPARSE (@4, $1, REAL, n); 2600 } 2601 ; 2602 2603function_arglist_optional: 2604 function_arglist_backup 2605 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_skip_backup DEFAULT 2606 { 2607 $$ = scm_cons (loc_on_copy (parser, @4, $1), $3); 2608 } 2609 | function_arglist_skip_backup BACKUP 2610 ; 2611 2612function_arglist_skip_backup: 2613 function_arglist_backup 2614 | EXPECT_OPTIONAL EXPECT_SCM function_arglist_skip_backup 2615 { 2616 $$ = scm_cons (loc_on_copy (parser, @3, $1), $3); 2617 } 2618 ; 2619 2620music_function_call: 2621 MUSIC_FUNCTION function_arglist { 2622 $$ = MAKE_SYNTAX (music_function, @$, 2623 $1, $2); 2624 } 2625 ; 2626 2627 2628optional_id: 2629 /**/ { $$ = SCM_EOL; } 2630 | '=' simple_string { 2631 $$ = $2; 2632 } 2633 ; 2634 2635// We must not have lookahead tokens parsed in lyric mode. In order 2636// to save confusion, we take almost the same set as permitted with 2637// \lyricmode and/or \lyrics. However, music identifiers are also 2638// allowed, and they obviously do not require switching into lyrics 2639// mode for parsing. 2640 2641lyric_mode_music: 2642 { 2643 parser->lexer_->push_lyric_state (); 2644 } grouped_music_list 2645 { 2646 parser->lexer_->pop_state (); 2647 $$ = $2; 2648 } 2649 | MUSIC_IDENTIFIER 2650 ; 2651 2652mode_changed_music: 2653 mode_changing_head grouped_music_list { 2654 if (scm_is_eq ($1, ly_symbol2scm ("chords"))) 2655 { 2656 $$ = MAKE_SYNTAX (unrelativable_music, @$, $2); 2657 } 2658 else 2659 { 2660 $$ = $2; 2661 } 2662 parser->lexer_->pop_state (); 2663 } 2664 | mode_changing_head_with_context optional_context_mods grouped_music_list { 2665 $$ = MAKE_SYNTAX (context_create, @$, $1, SCM_EOL, $2, $3); 2666 if (scm_is_eq ($1, ly_symbol2scm ("ChordNames"))) 2667 { 2668 $$ = MAKE_SYNTAX (unrelativable_music, @$, $$); 2669 } 2670 parser->lexer_->pop_state (); 2671 } 2672 ; 2673 2674mode_changing_head: 2675 NOTEMODE { 2676 parser->lexer_->push_note_state (); 2677 2678 $$ = ly_symbol2scm ("notes"); 2679 } 2680 | DRUMMODE 2681 { 2682 parser->lexer_->push_drum_state (); 2683 $$ = ly_symbol2scm ("drums"); 2684 } 2685 | FIGUREMODE { 2686 parser->lexer_->push_figuredbass_state (); 2687 2688 $$ = ly_symbol2scm ("figures"); 2689 } 2690 | CHORDMODE { 2691 SCM mods = parser->lexer_->lookup_identifier_symbol (ly_symbol2scm ("chordmodifiers")); 2692 parser->lexer_->chordmodifier_tab_ = alist_to_hashq (mods); 2693 parser->lexer_->push_chord_state (); 2694 $$ = ly_symbol2scm ("chords"); 2695 2696 } 2697 | LYRICMODE 2698 { parser->lexer_->push_lyric_state (); 2699 $$ = ly_symbol2scm ("lyrics"); 2700 } 2701 ; 2702 2703mode_changing_head_with_context: 2704 DRUMS { 2705 parser->lexer_->push_drum_state(); 2706 $$ = ly_symbol2scm ("DrumStaff"); 2707 } 2708 | FIGURES { 2709 parser->lexer_->push_figuredbass_state (); 2710 2711 $$ = ly_symbol2scm ("FiguredBass"); 2712 } 2713 | CHORDS { 2714 SCM mods = parser->lexer_->lookup_identifier_symbol (ly_symbol2scm ("chordmodifiers")); 2715 parser->lexer_->chordmodifier_tab_ = alist_to_hashq (mods); 2716 parser->lexer_->push_chord_state (); 2717 $$ = ly_symbol2scm ("ChordNames"); 2718 } 2719 | LYRICS 2720 { parser->lexer_->push_lyric_state (); 2721 $$ = ly_symbol2scm ("Lyrics"); 2722 } 2723 ; 2724 2725context_change: 2726 CHANGE symbol '=' simple_string { 2727 $$ = MAKE_SYNTAX (context_change, @$, $2, $4); 2728 } 2729 ; 2730 2731 2732property_path: 2733 symbol_list_rev { 2734 $$ = scm_reverse_x ($1, SCM_EOL); 2735 } 2736 ; 2737 2738property_operation: 2739 symbol '=' scalar { 2740 $$ = scm_list_3 (ly_symbol2scm ("assign"), $1, $3); 2741 } 2742 | UNSET symbol { 2743 $$ = scm_list_2 (ly_symbol2scm ("unset"), $2); 2744 } 2745 | OVERRIDE revert_arg '=' scalar { 2746 if (scm_ilength ($2) < 2) { 2747 parser->parser_error (@2, _("bad grob property path")); 2748 $$ = SCM_UNDEFINED; 2749 } else { 2750 $$ = scm_cons (ly_symbol2scm ("push"), 2751 scm_cons2 (scm_car ($2), 2752 $4, 2753 scm_cdr ($2))); 2754 } 2755 } 2756 | REVERT revert_arg { 2757 $$ = scm_cons (ly_symbol2scm ("pop"), $2); 2758 } 2759 ; 2760 2761// This is all quite awkward for the sake of substantial backward 2762// compatibility while at the same time allowing a more "natural" form 2763// of specification not separating grob specification from grob 2764// property path. The purpose of this definition of revert_arg is to 2765// allow the symbol list which specifies grob and property to revert 2766// to be optionally be split into two parts after the grob (which in 2767// this case is just the first element of the list). symbol_list_part 2768// is only one path component, but it can be parsed without lookahead, 2769// so we can follow it with a synthetic BACKUP token when needed. If 2770// the first symbol_list_part already contains multiple elements (only 2771// possible if a Scheme expression provides them), we just parse for 2772// additional elements introduced by '.', which is what the 2773// SYMBOL_LIST backup in connection with the immediately following 2774// rule using symbol_list_arg does. 2775// 2776// As long as we don't have our coffers filled with both grob and at 2777// least one grob property specification, the rest of the required 2778// symbol list chain may be provided either with or without a leading 2779// dot. This is for both allowing the traditional 2780// \revert Accidental #'color 2781// as well as well as the "naive" form 2782// \revert Accidental.color 2783 2784revert_arg: 2785 revert_arg_backup BACKUP symbol_list_arg 2786 { 2787 $$ = $3; 2788 } 2789 ; 2790 2791revert_arg_backup: 2792 revert_arg_part 2793 { 2794 if (scm_is_null ($1) 2795 || scm_is_null (scm_cdr ($1))) 2796 MYBACKUP (SCM_ARG, $1, @1); 2797 else 2798 MYBACKUP (SYMBOL_LIST, scm_reverse_x ($1, SCM_EOL), @1); 2799 } 2800 ; 2801 2802// revert_arg_part delivers results in reverse 2803revert_arg_part: 2804 symbol_list_part 2805 | revert_arg_backup BACKUP SCM_ARG '.' symbol_list_part 2806 { 2807 $$ = scm_append_x (scm_list_2 ($5, $3)); 2808 } 2809 | revert_arg_backup BACKUP SCM_ARG ',' symbol_list_part 2810 { 2811 $$ = scm_append_x (scm_list_2 ($5, $3)); 2812 } 2813 | revert_arg_backup BACKUP SCM_ARG symbol_list_part 2814 { 2815 $$ = scm_append_x (scm_list_2 ($4, $3)); 2816 } 2817 ; 2818 2819context_def_mod: 2820 CONSISTS { $$ = ly_symbol2scm ("consists"); } 2821 | REMOVE { $$ = ly_symbol2scm ("remove"); } 2822 2823 | ACCEPTS { $$ = ly_symbol2scm ("accepts"); } 2824 | DEFAULTCHILD { $$ = ly_symbol2scm ("default-child"); } 2825 | DENIES { $$ = ly_symbol2scm ("denies"); } 2826 2827 | ALIAS { $$ = ly_symbol2scm ("alias"); } 2828 | TYPE { $$ = ly_symbol2scm ("translator-type"); } 2829 | DESCRIPTION { $$ = ly_symbol2scm ("description"); } 2830 | NAME { $$ = ly_symbol2scm ("context-name"); } 2831 ; 2832 2833context_mod: 2834 property_operation { $$ = $1; } 2835 | context_def_mod STRING { 2836 $$ = scm_list_2 ($1, $2); 2837 } 2838 | context_def_mod SYMBOL { 2839 $$ = scm_list_2 ($1, $2); 2840 } 2841 | context_def_mod embedded_scm 2842 { 2843 if (!scm_is_string ($2) 2844 && !scm_is_eq ($1, ly_symbol2scm ("consists")) 2845 && !scm_is_eq ($1, ly_symbol2scm ("remove"))) 2846 { 2847 $$ = SCM_EOL; 2848 parser->parser_error (@1, _ ("only \\consists and \\remove take non-string argument.")); 2849 } 2850 else 2851 { 2852 $$ = scm_list_2 ($1, $2); 2853 } 2854 } 2855 ; 2856 2857// If defined, at least two members. 2858grob_prop_spec: 2859 symbol_list_rev 2860 { 2861 SCM l = scm_reverse_x ($1, SCM_EOL); 2862 if (scm_is_pair (l) 2863 && from_scm<bool> 2864 (scm_object_property (scm_car (l), 2865 ly_symbol2scm ("is-grob?")))) 2866 l = scm_cons (ly_symbol2scm ("Bottom"), l); 2867 if (scm_is_null (l) || scm_is_null (scm_cdr (l))) { 2868 parser->parser_error (@1, _ ("bad grob property path")); 2869 l = SCM_UNDEFINED; 2870 } 2871 $$ = l; 2872 } 2873 ; 2874 2875// If defined, at least three members 2876grob_prop_path: 2877 grob_prop_spec 2878 { 2879 if (!SCM_UNBNDP ($1) && scm_is_null (scm_cddr ($1))) 2880 { 2881 parser->parser_error (@1, _ ("bad grob property path")); 2882 $$ = SCM_UNDEFINED; 2883 } 2884 } 2885 | grob_prop_spec property_path 2886 { 2887 if (!SCM_UNBNDP ($1)) { 2888 $$ = scm_append_x (scm_list_2 ($1, $2)); 2889 if (scm_is_null (scm_cddr ($$))) { 2890 parser->parser_error (@$, _ ("bad grob property path")); 2891 $$ = SCM_UNDEFINED; 2892 } 2893 } 2894 2895 } 2896 ; 2897 2898// Exactly two elements or undefined 2899context_prop_spec: 2900 symbol_list_rev 2901 { 2902 SCM l = scm_reverse_x ($1, SCM_EOL); 2903 switch (scm_ilength (l)) { 2904 case 1: 2905 l = scm_cons (ly_symbol2scm ("Bottom"), l); 2906 case 2: 2907 break; 2908 default: 2909 parser->parser_error (@1, _ ("bad context property path")); 2910 l = SCM_UNDEFINED; 2911 } 2912 $$ = l; 2913 } 2914 ; 2915 2916 2917// This is all quite awkward for the sake of substantial backward 2918// compatibility while at the same time allowing a more "natural" form 2919// of specification not separating grob specification from grob 2920// property path. The purpose of this definition of 2921// simple_revert_context is to allow the symbol list which specifies 2922// grob and property to revert to be optionally be split into two 2923// parts after the grob (which may be preceded by a context 2924// specification, a case which we distinguish by checking whether the 2925// first symbol is a valid grob symbol instead). 2926// 2927// See revert_arg above for the main work horse of this arrangement. 2928// simple_revert_context just caters for the context and delegates the 2929// rest of the job to revert_arg. 2930 2931simple_revert_context: 2932 symbol_list_part 2933 { 2934 $1 = scm_reverse_x ($1, SCM_EOL); 2935 if (scm_is_null ($1) 2936 || from_scm<bool> 2937 (scm_object_property (scm_car ($1), 2938 ly_symbol2scm ("is-grob?")))) { 2939 $$ = ly_symbol2scm ("Bottom"); 2940 parser->lexer_->push_extra_token (@1, SCM_IDENTIFIER, $1); 2941 } else { 2942 $$ = scm_car ($1); 2943 parser->lexer_->push_extra_token (@1, SCM_IDENTIFIER, 2944 scm_cdr ($1)); 2945 } 2946 } 2947 ; 2948 2949music_property_def: 2950 OVERRIDE grob_prop_path '=' scalar { 2951 if (SCM_UNBNDP ($2)) 2952 $$ = MAKE_SYNTAX (void_music, @$); 2953 else 2954 $$ = MAKE_SYNTAX (property_override, @$, 2955 scm_car ($2), 2956 scm_cdr ($2), 2957 $4); 2958 } 2959 | REVERT simple_revert_context revert_arg { 2960 $$ = MAKE_SYNTAX (property_revert, @$, $2, $3); 2961 } 2962 | SET context_prop_spec '=' scalar { 2963 if (SCM_UNBNDP ($2)) 2964 $$ = MAKE_SYNTAX (void_music, @$); 2965 else 2966 $$ = MAKE_SYNTAX (property_set, @$, 2967 scm_car ($2), 2968 scm_cadr ($2), 2969 $4); 2970 } 2971 | UNSET context_prop_spec { 2972 if (SCM_UNBNDP ($2)) 2973 $$ = MAKE_SYNTAX (void_music, @$); 2974 else 2975 $$ = MAKE_SYNTAX (property_unset, @$, 2976 scm_car ($2), 2977 scm_cadr ($2)); 2978 } 2979 ; 2980 2981string: 2982 STRING 2983 | SYMBOL 2984 | full_markup 2985 ; 2986 2987text: 2988 STRING 2989 | SYMBOL 2990 | full_markup 2991 | embedded_scm_bare 2992 { 2993 if (Text_interface::is_markup ($1)) { 2994 $$ = $1; 2995 } else { 2996 parser->parser_error (@1, (_ ("markup expected"))); 2997 $$ = scm_string (SCM_EOL); 2998 } 2999 } 3000 ; 3001 3002simple_string: STRING 3003 | SYMBOL 3004 | embedded_scm_bare 3005 { 3006 if (scm_is_string ($1)) { 3007 $$ = $1; 3008 } else { 3009 parser->parser_error (@1, (_ ("simple string expected"))); 3010 $$ = scm_string (SCM_EOL); 3011 } 3012 } 3013 ; 3014 3015symbol: 3016 STRING { 3017 $$ = scm_string_to_symbol ($1); 3018 } 3019 | SYMBOL 3020 { 3021 if (!is_regular_identifier ($1, false)) 3022 parser->parser_error (@1, (_ ("symbol expected"))); 3023 $$ = scm_string_to_symbol ($1); 3024 } 3025 | embedded_scm_bare 3026 { 3027 // This is a bit of overkill but makes the same 3028 // routine responsible for all symbol interpretations. 3029 $$ = try_string_variants (Guile_user::symbol_p, $1); 3030 if (SCM_UNBNDP ($$)) 3031 { 3032 parser->parser_error (@1, (_ ("symbol expected"))); 3033 // Generate a unique symbol in case it is used 3034 // for an assignment or similar 3035 $$ = scm_make_symbol (ly_string2scm ("undefined")); 3036 } 3037 } 3038 ; 3039 3040scalar: 3041 embedded_scm_arg 3042 | pitch_or_music 3043 | SCM_IDENTIFIER 3044 | bare_number 3045 // The following is a rather defensive variant of admitting 3046 // negative numbers: the grammar would permit number_factor or 3047 // even number_expression. However, function arguments allow 3048 // only this simple kind of negative number, so to have things 3049 // like \tweak and \override behave reasonably similar, it 3050 // makes sense to rule out things like -- which are rather an 3051 // accent in function argument contexts. 3052 | '-' bare_number 3053 { 3054 $$ = scm_difference ($2, SCM_UNDEFINED); 3055 } 3056 | string 3057 | symbol_list_part_bare '.' property_path 3058 { 3059 $$ = scm_reverse_x ($1, $3); 3060 } 3061 | symbol_list_part_bare ',' property_path 3062 { 3063 $$ = scm_reverse_x ($1, $3); 3064 } 3065 ; 3066 3067event_chord: 3068 simple_element post_events { 3069 // Let the rhythmic music iterator sort this mess out. 3070 if (scm_is_pair ($2)) { 3071 set_property (unsmob<Music> ($$), "articulations", 3072 scm_reverse_x ($2, SCM_EOL)); 3073 } 3074 } %prec ':' 3075 | CHORD_REPETITION optional_notemode_duration post_events { 3076 $$ = MAKE_SYNTAX (repetition_chord, @$, 3077 $2, scm_reverse_x ($3, SCM_EOL)); 3078 } %prec ':' 3079 | MULTI_MEASURE_REST optional_notemode_duration post_events { 3080 $$ = MAKE_SYNTAX (multi_measure_rest, @$, $2, 3081 scm_reverse_x ($3, SCM_EOL)); 3082 } %prec ':' 3083 | tempo_event 3084 | note_chord_element 3085 ; 3086 3087 3088note_chord_element: 3089 chord_body optional_notemode_duration post_events 3090 { 3091 Music *m = unsmob<Music> ($1); 3092 SCM dur = unsmob<Duration> ($2)->smobbed_copy (); 3093 SCM es = get_property (m, "elements"); 3094 SCM postevs = scm_reverse_x ($3, SCM_EOL); 3095 3096 for (SCM s = es; scm_is_pair (s); s = scm_cdr (s)) 3097 set_property (unsmob<Music> (scm_car (s)), "duration", dur); 3098 es = ly_append2 (es, postevs); 3099 3100 set_property (m, "elements", es); 3101 m->set_spot (parser->lexer_->override_input (@$)); 3102 $$ = m->self_scm (); 3103 } %prec ':' 3104 ; 3105 3106chord_body: 3107 ANGLE_OPEN chord_body_elements ANGLE_CLOSE 3108 { 3109 $$ = MAKE_SYNTAX (event_chord, @$, 3110 reverse_music_list (parser, @$, 3111 $2, false, false)); 3112 } 3113 | FIGURE_OPEN figure_list FIGURE_CLOSE 3114 { 3115 $$ = MAKE_SYNTAX (event_chord, @$, scm_reverse_x ($2, SCM_EOL)); 3116 } 3117 ; 3118 3119chord_body_elements: 3120 /* empty */ { $$ = SCM_EOL; } 3121 | chord_body_elements chord_body_element { 3122 if (unsmob<Music> ($2)) 3123 $$ = scm_cons ($2, $1); 3124 } 3125 ; 3126 3127chord_body_element: 3128 pitch_or_tonic_pitch exclamations questions octave_check post_events %prec ':' 3129 { 3130 bool q = from_scm<bool> ($3); 3131 bool ex = from_scm<bool> ($2); 3132 SCM check = $4; 3133 SCM post = $5; 3134 3135 Music *n = MY_MAKE_MUSIC ("NoteEvent", @$); 3136 set_property (n, "pitch", $1); 3137 if (q) 3138 set_property (n, "cautionary", SCM_BOOL_T); 3139 if (ex || q) 3140 set_property (n, "force-accidental", SCM_BOOL_T); 3141 3142 if (scm_is_pair (post)) { 3143 SCM arts = scm_reverse_x (post, SCM_EOL); 3144 set_property (n, "articulations", arts); 3145 } 3146 if (scm_is_number (check)) 3147 { 3148 int q = scm_to_int (check); 3149 set_property (n, "absolute-octave", to_scm (q-1)); 3150 } 3151 3152 $$ = n->unprotect (); 3153 } 3154 | DRUM_PITCH post_events %prec ':' { 3155 Music *n = MY_MAKE_MUSIC ("NoteEvent", @$); 3156 set_property (n, "drum-type", $1); 3157 3158 if (scm_is_pair ($2)) { 3159 SCM arts = scm_reverse_x ($2, SCM_EOL); 3160 set_property (n, "articulations", arts); 3161 } 3162 $$ = n->unprotect (); 3163 } 3164 | music_function_chord_body 3165 { 3166 Music *m = unsmob<Music> ($1); 3167 3168 if (m && !m->is_mus_type ("post-event")) { 3169 while (m && m->is_mus_type ("music-wrapper-music")) { 3170 $$ = get_property (m, "element"); 3171 m = unsmob<Music> ($$); 3172 } 3173 3174 if (!(m && m->is_mus_type ("rhythmic-event"))) { 3175 parser->parser_error (@$, _ ("not a rhythmic event")); 3176 $$ = SCM_UNSPECIFIED; 3177 } 3178 } 3179 } 3180 | post_event 3181 ; 3182 3183music_function_chord_body: 3184 music_function_call 3185 | MUSIC_IDENTIFIER 3186 | embedded_scm 3187 ; 3188 3189event_function_event: 3190 EVENT_FUNCTION function_arglist { 3191 $$ = MAKE_SYNTAX (music_function, @$, 3192 $1, $2); 3193 } 3194 ; 3195 3196post_events: 3197 /* empty */ { 3198 $$ = SCM_EOL; 3199 } 3200 | post_events post_event { 3201 $$ = post_event_cons ($2, $1); 3202 } 3203 ; 3204 3205post_event_nofinger: 3206 direction_less_event { 3207 $$ = $1; 3208 } 3209 | script_dir music_function_call { 3210 Music *m = unsmob<Music> ($2); 3211 if (!m->is_mus_type ("post-event")) { 3212 parser->parser_error (@2, _ ("post-event expected")); 3213 $$ = SCM_UNSPECIFIED; 3214 } else { 3215 m->set_spot (parser->lexer_->override_input (@$)); 3216 if (!SCM_UNBNDP ($1)) 3217 set_property (m, "direction", $1); 3218 $$ = $2; 3219 } 3220 } 3221 | HYPHEN { 3222 if (!parser->lexer_->is_lyric_state ()) 3223 parser->parser_error (@1, _ ("have to be in Lyric mode for lyrics")); 3224 $$ = MY_MAKE_MUSIC ("HyphenEvent", @$)->unprotect (); 3225 } 3226 | EXTENDER { 3227 if (!parser->lexer_->is_lyric_state ()) 3228 parser->parser_error (@1, _ ("have to be in Lyric mode for lyrics")); 3229 $$ = MY_MAKE_MUSIC ("ExtenderEvent", @$)->unprotect (); 3230 } 3231 | script_dir direction_reqd_event { 3232 if (Music *m = unsmob<Music> ($2)) { 3233 m->set_spot (parser->lexer_->override_input (@$)); 3234 if (!SCM_UNBNDP ($1)) 3235 { 3236 set_property (m, "direction", $1); 3237 } 3238 } 3239 $$ = $2; 3240 } 3241 | script_dir direction_less_event { 3242 Music *m = unsmob<Music> ($2); 3243 m->set_spot (parser->lexer_->override_input (@$)); 3244 if (!SCM_UNBNDP ($1)) 3245 set_property (m, "direction", $1); 3246 $$ = $2; 3247 } 3248 | '^' fingering 3249 { 3250 Music *m = unsmob<Music> ($2); 3251 m->set_spot (parser->lexer_->override_input (@$)); 3252 set_property (m, "direction", to_scm (UP)); 3253 $$ = $2; 3254 } 3255 | '_' fingering 3256 { 3257 Music *m = unsmob<Music> ($2); 3258 m->set_spot (parser->lexer_->override_input (@$)); 3259 set_property (m, "direction", to_scm (DOWN)); 3260 $$ = $2; 3261 } 3262 ; 3263 3264post_event: 3265 post_event_nofinger 3266 | '-' fingering { 3267 unsmob<Music> ($2)->set_spot (parser->lexer_->override_input (@$)); 3268 $$ = $2; 3269 } 3270 ; 3271 3272string_number_event: 3273 E_UNSIGNED { 3274 Music *s = MY_MAKE_MUSIC ("StringNumberEvent", @$); 3275 set_property (s, "string-number", $1); 3276 $$ = s->unprotect (); 3277 } 3278 ; 3279 3280direction_less_event: 3281 string_number_event 3282 | EVENT_IDENTIFIER { 3283 $$ = $1; 3284 } 3285 | tremolo_type { 3286 Music *a = MY_MAKE_MUSIC ("TremoloEvent", @$); 3287 set_property (a, "tremolo-type", $1); 3288 $$ = a->unprotect (); 3289 } 3290 | event_function_event 3291 ; 3292 3293direction_reqd_event: 3294 gen_text_def { 3295 $$ = $1; 3296 } 3297 | script_abbreviation { 3298 SCM sym = ly_symbol2scm (("dash" + ly_scm2string ($1)).c_str()); 3299 SCM s = parser->lexer_->lookup_identifier_symbol (sym); 3300 if (scm_is_string (s)) { 3301 Music *a = MY_MAKE_MUSIC ("ArticulationEvent", @$); 3302 set_property (a, "articulation-type", s); 3303 $$ = a->unprotect (); 3304 } else { 3305 Music *original = unsmob<Music> (s); 3306 if (original && original->is_mus_type ("post-event")) { 3307 Music *a = original->clone (); 3308 // origin will be set by post_event_nofinger 3309 $$ = a->unprotect (); 3310 } else { 3311 parser->parser_error (@1, _ ("expecting string or post-event as script definition")); 3312 $$ = SCM_UNSPECIFIED; 3313 } 3314 } 3315 } 3316 ; 3317 3318octave_check: 3319 /**/ { $$ = SCM_EOL; } 3320 | '=' quotes { $$ = $2; } 3321 ; 3322 3323quotes: 3324 /* empty */ 3325 { 3326 $$ = SCM_INUM0; 3327 } %prec ':' 3328 | sub_quotes %prec ':' 3329 | sup_quotes %prec ':' 3330 ; 3331 3332// no quotes, no error: pass *undefined* in that case. 3333erroneous_quotes: 3334 quotes { 3335 if (scm_is_eq (SCM_INUM0, $1)) 3336 $$ = SCM_UNDEFINED; 3337 } 3338 ; 3339 3340sup_quotes: 3341 '\'' { 3342 $$ = to_scm (1); 3343 } 3344 | sup_quotes '\'' { 3345 $$ = scm_oneplus ($1); 3346 } 3347 ; 3348 3349sub_quotes: 3350 ',' { 3351 $$ = to_scm (-1); 3352 } 3353 | sub_quotes ',' { 3354 $$ = scm_oneminus ($1); 3355 } 3356 ; 3357 3358steno_pitch: 3359 NOTENAME_PITCH quotes { 3360 if (!scm_is_eq (SCM_INUM0, $2)) 3361 { 3362 Pitch p = *unsmob<Pitch> ($1); 3363 p = p.transposed (Pitch (scm_to_int ($2), 0)); 3364 $$ = p.smobbed_copy (); 3365 } 3366 } 3367 ; 3368 3369/* 3370ugh. duplication 3371*/ 3372 3373steno_tonic_pitch: 3374 TONICNAME_PITCH quotes { 3375 if (!scm_is_eq (SCM_INUM0, $2)) 3376 { 3377 Pitch p = *unsmob<Pitch> ($1); 3378 p = p.transposed (Pitch (scm_to_int ($2), 0)); 3379 $$ = p.smobbed_copy (); 3380 } 3381 } 3382 ; 3383 3384pitch: 3385 steno_pitch 3386 | PITCH_IDENTIFIER quotes { 3387 if (!scm_is_eq (SCM_INUM0, $2)) 3388 { 3389 Pitch p = *unsmob<Pitch> ($1); 3390 p = p.transposed (Pitch (scm_to_int ($2), 0)); 3391 $$ = p.smobbed_copy (); 3392 } 3393 } 3394 ; 3395 3396pitch_or_tonic_pitch: 3397 pitch 3398 | steno_tonic_pitch 3399 ; 3400 3401gen_text_def: 3402 full_markup { 3403 Music *t = MY_MAKE_MUSIC ("TextScriptEvent", @$); 3404 set_property (t, "text", $1); 3405 $$ = t->unprotect (); 3406 } 3407 | STRING { 3408 Music *t = MY_MAKE_MUSIC ("TextScriptEvent", @$); 3409 set_property (t, "text", 3410 make_simple_markup ($1)); 3411 $$ = t->unprotect (); 3412 } 3413 | SYMBOL { 3414 // Flag a warning? could be unintentional 3415 Music *t = MY_MAKE_MUSIC ("TextScriptEvent", @$); 3416 set_property (t, "text", 3417 make_simple_markup ($1)); 3418 $$ = t->unprotect (); 3419 } 3420 | embedded_scm 3421 { 3422 // Could be using this for every gen_text_def but for speed 3423 $$ = MAKE_SYNTAX (create_script, @1, $1); 3424 } 3425 ; 3426 3427fingering: 3428 UNSIGNED { 3429 Music *t = MY_MAKE_MUSIC ("FingeringEvent", @$); 3430 set_property (t, "digit", $1); 3431 $$ = t->unprotect (); 3432 } 3433 ; 3434 3435script_abbreviation: 3436 '^' { 3437 $$ = scm_from_ascii_string ("Hat"); 3438 } 3439 | '+' { 3440 $$ = scm_from_ascii_string ("Plus"); 3441 } 3442 | '-' { 3443 $$ = scm_from_ascii_string ("Dash"); 3444 } 3445 | '!' { 3446 $$ = scm_from_ascii_string ("Bang"); 3447 } 3448 | ANGLE_CLOSE { 3449 $$ = scm_from_ascii_string ("Larger"); 3450 } 3451 | '.' { 3452 $$ = scm_from_ascii_string ("Dot"); 3453 } 3454 | '_' { 3455 $$ = scm_from_ascii_string ("Underscore"); 3456 } 3457 ; 3458 3459script_dir: 3460 '_' { $$ = to_scm (DOWN); } 3461 | '^' { $$ = to_scm (UP); } 3462 | '-' { $$ = SCM_UNDEFINED; } 3463 ; 3464 3465maybe_notemode_duration: 3466 { 3467 $$ = SCM_UNDEFINED; 3468 } %prec ':' 3469 | duration { 3470 $$ = $1; 3471 parser->default_duration_ = *unsmob<Duration> ($$); 3472 } 3473; 3474 3475 3476optional_notemode_duration: 3477 maybe_notemode_duration 3478 { 3479 if (SCM_UNBNDP ($$)) 3480 $$ = parser->default_duration_.smobbed_copy (); 3481 } 3482 ; 3483 3484steno_duration: 3485 UNSIGNED dots { 3486 $$ = make_duration ($1, scm_to_int ($2)); 3487 if (SCM_UNBNDP ($$)) 3488 { 3489 parser->parser_error (@1, _ ("not a duration")); 3490 $$ = Duration ().smobbed_copy (); 3491 } 3492 } 3493 | DURATION_IDENTIFIER dots { 3494 $$ = make_duration ($1, scm_to_int ($2)); 3495 } 3496 ; 3497 3498duration: 3499 steno_duration multipliers { 3500 $$ = make_duration ($1, 0, $2); 3501 } 3502 ; 3503 3504dots: 3505 /* empty */ { 3506 $$ = SCM_INUM0; 3507 } 3508 | dots '.' { 3509 $$ = scm_oneplus ($1); 3510 } 3511 ; 3512 3513multiplier_scm: 3514 NUMBER_IDENTIFIER 3515 | embedded_scm_bare 3516 ; 3517 3518multipliers: 3519 /* empty */ 3520 { 3521 $$ = SCM_UNDEFINED; 3522 } 3523 | multipliers '*' UNSIGNED 3524 { 3525 if (!SCM_UNBNDP ($1)) 3526 $$ = scm_product ($1, $3); 3527 else 3528 $$ = $3; 3529 } 3530 | multipliers '*' FRACTION 3531 { 3532 if (!SCM_UNBNDP ($1)) 3533 $$ = scm_product ($1, scm_divide (scm_car ($3), 3534 scm_cdr ($3))); 3535 else 3536 $$ = scm_divide (scm_car ($3), scm_cdr ($3)); 3537 } 3538 | multipliers '*' multiplier_scm 3539 { 3540 if (scm_is_false (Lily::scale_p ($3))) 3541 { 3542 parser->parser_error (@3, _ ("not a multiplier")); 3543 } else if (SCM_UNBNDP ($1)) 3544 $$ = Lily::scale_to_factor ($3); 3545 else 3546 $$ = scm_product ($1, Lily::scale_to_factor ($3)); 3547 } 3548 ; 3549 3550tremolo_type: 3551 ':' { 3552 $$ = to_scm (parser->default_tremolo_type_); 3553 } 3554 | ':' UNSIGNED { 3555 if (SCM_UNBNDP (make_duration ($2))) { 3556 parser->parser_error (@2, _ ("not a duration")); 3557 $$ = to_scm (parser->default_tremolo_type_); 3558 } else { 3559 $$ = $2; 3560 parser->default_tremolo_type_ = scm_to_int ($2); 3561 } 3562 } 3563 ; 3564 3565bass_number: 3566 UNSIGNED 3567 | STRING 3568 | SYMBOL 3569 | full_markup 3570 | embedded_scm_bare 3571 { 3572 // as an integer, it needs to be non-negative, and otherwise 3573 // it needs to be suitable as a markup. 3574 if (scm_is_integer ($1) 3575 ? scm_is_true (scm_negative_p ($1)) 3576 : !Text_interface::is_markup ($1)) 3577 { 3578 parser->parser_error (@1, _ ("bass number expected")); 3579 $$ = SCM_INUM0; 3580 } 3581 } 3582 ; 3583 3584bass_figure: 3585 FIGURE_SPACE { 3586 Music *bfr = MY_MAKE_MUSIC ("BassFigureEvent", @$); 3587 $$ = bfr->unprotect (); 3588 } 3589 | bass_number { 3590 Music *bfr = MY_MAKE_MUSIC ("BassFigureEvent", @$); 3591 $$ = bfr->self_scm (); 3592 3593 if (scm_is_number ($1)) 3594 set_property (bfr, "figure", $1); 3595 else if (Text_interface::is_markup ($1)) 3596 set_property (bfr, "text", $1); 3597 3598 bfr->unprotect (); 3599 } 3600 | bass_figure ']' { 3601 $$ = $1; 3602 set_property (unsmob<Music> ($1), "bracket-stop", SCM_BOOL_T); 3603 } 3604 | bass_figure FIGURE_ALTERATION_EXPR { 3605 Music *m = unsmob<Music> ($1); 3606 3607 if (scm_is_number (get_property (m, "alteration"))) 3608 m->warning (_f ("Dropping surplus alteration symbols for bass figure.")); 3609 else { 3610 string alter_expr = ly_scm2string ($2); 3611 Rational alter (0); 3612 bool bracket = false; 3613 3614 for (string::iterator it=alter_expr.begin(); it != alter_expr.end (); it++) 3615 { 3616 int c = *it & 0xff; 3617 3618 /* The friendly lexer guarantees that '[' has its matching ']', 3619 so we don't have to check here. */ 3620 if (c == '[') bracket = true; 3621 3622 /* "!" resets the counter: we mimic this traditional (pre-2.23.4) behavior. */ 3623 else if (c == '!') alter = 0; 3624 else if (c == '+') alter += SHARP_ALTERATION; 3625 else if (c == '-') alter += FLAT_ALTERATION; 3626 } 3627 3628 set_property (m, "alteration", to_scm (alter)); 3629 if (bracket) 3630 set_property (m, "alteration-bracket", SCM_BOOL_T); 3631 } 3632 } 3633 | bass_figure figured_bass_modification { 3634 Music *m = unsmob<Music> ($1); 3635 set_property (m, $2, SCM_BOOL_T); 3636 } 3637 ; 3638 3639 3640figured_bass_modification: 3641 E_PLUS { 3642 $$ = ly_symbol2scm ("augmented"); 3643 } 3644 | E_EXCLAMATION { 3645 $$ = ly_symbol2scm ("no-continuation"); 3646 } 3647 | '/' { 3648 $$ = ly_symbol2scm ("diminished"); 3649 } 3650 | E_BACKSLASH { 3651 $$ = ly_symbol2scm ("augmented-slash"); 3652 } 3653 ; 3654 3655br_bass_figure: 3656 bass_figure { 3657 $$ = $1; 3658 } 3659 | '[' bass_figure { 3660 $$ = $2; 3661 set_property (unsmob<Music> ($$), "bracket-start", SCM_BOOL_T); 3662 } 3663 ; 3664 3665figure_list: 3666 /**/ { 3667 $$ = SCM_EOL; 3668 } 3669 | figure_list br_bass_figure { 3670 $$ = scm_cons ($2, $1); 3671 } 3672 ; 3673 3674optional_rest: 3675 /**/ { $$ = SCM_BOOL_F; } 3676 | REST { $$ = SCM_BOOL_T; } 3677 ; 3678 3679pitch_or_music: 3680// The erroneous_quotes element is for input such as a1'' which is a 3681// typical note entry error that we don't want the parser to get 3682// confused about. The resulting grammar, however, is inconsistent 3683// enough that accepting it is not doing anybody a favor. 3684 pitch exclamations questions octave_check maybe_notemode_duration erroneous_quotes optional_rest post_events { 3685 if (!parser->lexer_->is_note_state ()) 3686 parser->parser_error (@1, _ ("have to be in Note mode for notes")); 3687 if (!SCM_UNBNDP ($6)) 3688 { 3689 // It's possible to get here without a 3690 // duration, like when there is no 3691 // octave_check but a question mark. But we 3692 // point out the most frequent error of an 3693 // interspersed duration specifically 3694 if (!SCM_UNBNDP ($5)) 3695 parser->parser_error (@6, _ ("octave marks must precede duration")); 3696 else 3697 parser->parser_error (@6, _ ("badly placed octave marks")); 3698 // Try sorting the quotes to where they likely belong 3699 if (scm_is_number ($4)) { 3700 $4 = scm_sum ($4, $6); 3701 } else { 3702 $1 = unsmob<Pitch> ($1)->transposed 3703 (Pitch (scm_to_int ($6), 0)).smobbed_copy (); 3704 } 3705 } 3706 3707 if (!SCM_UNBNDP ($2) 3708 || !SCM_UNBNDP ($3) 3709 || scm_is_number ($4) 3710 || !SCM_UNBNDP ($5) 3711 || scm_is_true ($7) 3712 || scm_is_pair ($8)) 3713 { 3714 Music *n = 0; 3715 if (scm_is_true ($7)) 3716 n = MY_MAKE_MUSIC ("RestEvent", @$); 3717 else 3718 n = MY_MAKE_MUSIC ("NoteEvent", @$); 3719 3720 set_property (n, "pitch", $1); 3721 if (SCM_UNBNDP ($5)) 3722 set_property (n, "duration", 3723 parser->default_duration_.smobbed_copy ()); 3724 else 3725 set_property (n, "duration", $5); 3726 3727 if (scm_is_number ($4)) 3728 { 3729 int q = scm_to_int ($4); 3730 set_property (n, "absolute-octave", to_scm (q-1)); 3731 } 3732 3733 if (from_scm<bool> ($3)) 3734 set_property (n, "cautionary", SCM_BOOL_T); 3735 if (from_scm<bool> ($2) || from_scm<bool> ($3)) 3736 set_property (n, "force-accidental", SCM_BOOL_T); 3737 if (scm_is_pair ($8)) 3738 set_property (n, "articulations", 3739 scm_reverse_x ($8, SCM_EOL)); 3740 $$ = n->unprotect (); 3741 } 3742 } %prec ':' 3743 | new_chord post_events { 3744 if (!parser->lexer_->is_chord_state ()) 3745 parser->parser_error (@1, _ ("have to be in Chord mode for chords")); 3746 if (scm_is_pair ($2)) { 3747 if (unsmob<Pitch> ($1)) 3748 $1 = make_chord_elements (@1, 3749 $1, 3750 parser->default_duration_.smobbed_copy (), 3751 SCM_EOL); 3752 3753 SCM elts = ly_append2 ($1, scm_reverse_x ($2, SCM_EOL)); 3754 3755 $$ = MAKE_SYNTAX (event_chord, @1, elts); 3756 } else if (!unsmob<Pitch> ($1)) 3757 $$ = MAKE_SYNTAX (event_chord, @1, $1); 3758 // A mere pitch drops through. 3759 } %prec ':' 3760 ; 3761 3762simple_element: 3763 DRUM_PITCH optional_notemode_duration { 3764 Music *n = MY_MAKE_MUSIC ("NoteEvent", @$); 3765 set_property (n, "duration", $2); 3766 set_property (n, "drum-type", $1); 3767 3768 $$ = n->unprotect (); 3769 } 3770 | RESTNAME optional_notemode_duration { 3771 Music *ev = 0; 3772 if (ly_scm2string ($1) == "s") { 3773 /* Space */ 3774 ev = MY_MAKE_MUSIC ("SkipEvent", @$); 3775 } 3776 else { 3777 ev = MY_MAKE_MUSIC ("RestEvent", @$); 3778 3779 } 3780 set_property (ev, "duration", $2); 3781 $$ = ev->unprotect (); 3782 } 3783 ; 3784 3785lyric_element: 3786 full_markup { 3787 if (!parser->lexer_->is_lyric_state ()) 3788 parser->parser_error (@1, _ ("markup outside of text script or \\lyricmode")); 3789 $$ = $1; 3790 } 3791 | SYMBOL { 3792 if (!parser->lexer_->is_lyric_state ()) 3793 parser->parser_error (@1, _f ("not a note name: %s", ly_scm2string ($1))); 3794 $$ = $1; 3795 } 3796 | STRING { 3797 if (!parser->lexer_->is_lyric_state ()) 3798 parser->parser_error (@1, _ ("string outside of text script or \\lyricmode")); 3799 $$ = $1; 3800 } 3801 | LYRIC_ELEMENT 3802 ; 3803 3804lyric_element_music: 3805 lyric_element optional_notemode_duration post_events { 3806 $$ = MAKE_SYNTAX (lyric_event, @$, $1, $2); 3807 if (scm_is_pair ($3)) 3808 set_property 3809 (unsmob<Music> ($$), "articulations", scm_reverse_x ($3, SCM_EOL)); 3810 } %prec ':' 3811 ; 3812 3813// Can return a single pitch rather than a list. 3814new_chord: 3815 steno_tonic_pitch maybe_notemode_duration { 3816 if (SCM_UNBNDP ($2)) 3817 $$ = $1; 3818 else 3819 $$ = make_chord_elements (@$, $1, $2, SCM_EOL); 3820 } 3821 | steno_tonic_pitch optional_notemode_duration chord_separator chord_items { 3822 SCM its = scm_reverse_x ($4, SCM_EOL); 3823 $$ = make_chord_elements (@$, $1, $2, scm_cons ($3, its)); 3824 } %prec ':' 3825 ; 3826 3827chord_items: 3828 /**/ { 3829 $$ = SCM_EOL; 3830 } 3831 | chord_items chord_item { 3832 $$ = scm_cons ($2, $$); 3833 } 3834 ; 3835 3836chord_separator: 3837 CHORD_COLON { 3838 $$ = ly_symbol2scm ("chord-colon"); 3839 } 3840 | CHORD_CARET { 3841 $$ = ly_symbol2scm ("chord-caret"); 3842 } 3843 | CHORD_SLASH steno_tonic_pitch { 3844 $$ = scm_list_2 (ly_symbol2scm ("chord-slash"), $2); 3845 } 3846 | CHORD_BASS steno_tonic_pitch { 3847 $$ = scm_list_2 (ly_symbol2scm ("chord-bass"), $2); 3848 } 3849 ; 3850 3851chord_item: 3852 chord_separator { 3853 $$ = $1; 3854 } 3855 | step_numbers { 3856 $$ = scm_reverse_x ($1, SCM_EOL); 3857 } 3858 | CHORD_MODIFIER { 3859 $$ = $1; 3860 } 3861 ; 3862 3863step_numbers: 3864 step_number { $$ = scm_cons ($1, SCM_EOL); } 3865 | step_numbers '.' step_number { 3866 $$ = scm_cons ($3, $$); 3867 } 3868 ; 3869 3870step_number: 3871 UNSIGNED { 3872 $$ = make_chord_step ($1, 0); 3873 } 3874 | UNSIGNED '+' { 3875 $$ = make_chord_step ($1, SHARP_ALTERATION); 3876 } 3877 | UNSIGNED CHORD_MINUS { 3878 $$ = make_chord_step ($1, FLAT_ALTERATION); 3879 } 3880 ; 3881 3882tempo_range: 3883 unsigned_number { 3884 $$ = $1; 3885 } %prec ':' 3886 | unsigned_number '-' unsigned_number { 3887 $$ = scm_cons ($1, $3); 3888 } 3889 ; 3890 3891/* 3892 UTILITIES 3893 3894TODO: should deprecate in favor of Scheme? 3895 3896 */ 3897number_expression: 3898 number_expression '+' number_term { 3899 $$ = scm_sum ($1, $3); 3900 } 3901 | number_expression '-' number_term { 3902 $$ = scm_difference ($1, $3); 3903 } 3904 | number_term 3905 ; 3906 3907number_term: 3908 number_factor { 3909 $$ = $1; 3910 } 3911 | number_factor '*' number_factor { 3912 $$ = scm_product ($1, $3); 3913 } 3914 | number_factor '/' number_factor { 3915 $$ = scm_divide ($1, $3); 3916 } 3917 ; 3918 3919number_factor: 3920 '-' number_factor { /* %prec UNARY_MINUS */ 3921 $$ = scm_difference ($2, SCM_UNDEFINED); 3922 } 3923 | bare_number 3924 ; 3925 3926bare_number_common: 3927 REAL 3928 | NUMBER_IDENTIFIER 3929 | REAL NUMBER_IDENTIFIER 3930 { 3931 $$ = scm_product ($1, $2); 3932 } 3933 ; 3934 3935bare_number: 3936 bare_number_common 3937 | UNSIGNED 3938 | UNSIGNED NUMBER_IDENTIFIER { 3939 $$ = scm_product ($1, $2); 3940 } 3941 ; 3942 3943unsigned_number: 3944 UNSIGNED 3945 | NUMBER_IDENTIFIER 3946 { 3947 if (!scm_is_integer ($1) 3948 || scm_is_true (scm_negative_p ($1))) 3949 { 3950 parser->parser_error (@1, _("not an unsigned integer")); 3951 $$ = SCM_INUM0; 3952 } 3953 } 3954 | embedded_scm 3955 { 3956 if (!scm_is_integer ($1) 3957 || scm_is_true (scm_negative_p ($1))) 3958 { 3959 parser->parser_error (@1, _("not an unsigned integer")); 3960 $$ = SCM_INUM0; 3961 } 3962 } 3963 ; 3964 3965exclamations: 3966 { $$ = SCM_UNDEFINED; } 3967 | exclamations '!' 3968 { 3969 if (SCM_UNBNDP ($1)) 3970 $$ = SCM_BOOL_T; 3971 else 3972 $$ = scm_not ($1); 3973 } 3974 ; 3975 3976questions: 3977// This precedence rule is rather weird. It triggers when '!' is 3978// encountered after a pitch, and is used for deciding whether to save 3979// this instead for a figure modification. This should not actually 3980// occur in practice as pitches and figures are generated in different 3981// modes. Using a greedy (%right) precedence makes sure that we don't 3982// get stuck in a wrong interpretation. 3983 { $$ = SCM_UNDEFINED; } %prec ':' 3984 | questions '?' 3985 { 3986 if (SCM_UNBNDP ($1)) 3987 $$ = SCM_BOOL_T; 3988 else 3989 $$ = scm_not ($1); 3990 } 3991 ; 3992 3993full_markup_list: 3994 MARKUPLIST 3995 { parser->lexer_->push_markup_state (); } 3996 markup_list { 3997 $$ = $3; 3998 parser->lexer_->pop_state (); 3999 } 4000 ; 4001 4002markup_mode: 4003 MARKUP 4004 { 4005 parser->lexer_->push_markup_state (); 4006 } 4007 ; 4008 4009// Sort-of ugly: We need this as markup of its own as well as in 4010// markup function assignments, without triggering lookahead or the 4011// '=' for assignments will be parsed in markup mode and not 4012// recognized. Worse: the next token following something like 4013// \markup "string" would be parsed in markup mode as well. 4014// 4015// So we make a single production here that's used either in markup or 4016// in assignment. 4017 4018markup_mode_word: 4019 markup_mode markup_word 4020 { 4021 $$ = $2; 4022 parser->lexer_->pop_state (); 4023 } 4024 ; 4025 4026 4027full_markup: 4028 markup_mode markup_top { 4029 $$ = $2; 4030 parser->lexer_->pop_state (); 4031 } 4032 | markup_mode_word 4033 { 4034 $$ = make_simple_markup ($1); 4035 } 4036 ; 4037 4038partial_markup: 4039 markup_mode markup_partial_function ETC 4040 { 4041 $$ = MAKE_SYNTAX (partial_markup, @2, $2); 4042 parser->lexer_->pop_state (); 4043 } 4044 ; 4045 4046markup_top: 4047 markup_list { 4048 $$ = scm_list_2 (Lily::line_markup, $1); 4049 } 4050 | markup_head_1_list simple_markup 4051 { 4052 $$ = scm_car (MAKE_SYNTAX (composed_markup_list, 4053 @2, $1, scm_list_1 ($2))); 4054 } 4055 | simple_markup_noword { 4056 $$ = $1; 4057 } 4058 ; 4059 4060markup_scm: 4061 embedded_scm 4062 { 4063 if (Text_interface::is_markup ($1)) 4064 MYBACKUP (MARKUP_IDENTIFIER, $1, @1); 4065 else if (Text_interface::is_markup_list ($1)) 4066 MYBACKUP (MARKUPLIST_IDENTIFIER, $1, @1); 4067 else { 4068 parser->parser_error (@1, _ ("not a markup")); 4069 MYBACKUP (MARKUP_IDENTIFIER, scm_string (SCM_EOL), @1); 4070 } 4071 } BACKUP 4072 ; 4073 4074 4075markup_list: 4076 markup_composed_list { 4077 $$ = $1; 4078 } 4079 | markup_uncomposed_list 4080 ; 4081 4082markup_uncomposed_list: 4083 markup_braced_list { 4084 $$ = $1; 4085 } 4086 | markup_command_list { 4087 $$ = scm_list_1 ($1); 4088 } 4089 | markup_scm MARKUPLIST_IDENTIFIER 4090 { 4091 $$ = $2; 4092 } 4093 | SCORELINES { 4094 parser->lexer_->push_note_state (); 4095 } '{' score_body '}' { 4096 Score *sc = unsmob<Score> ($4); 4097 sc->origin ()->set_spot (@$); 4098 if (sc->defs_.empty ()) { 4099 Output_def *od = get_layout (parser); 4100 sc->add_output_def (od); 4101 od->unprotect (); 4102 } 4103 $$ = scm_list_1 (scm_list_2 (Lily::score_lines_markup_list, $4)); 4104 parser->lexer_->pop_state (); 4105 } 4106 ; 4107 4108markup_composed_list: 4109 markup_head_1_list markup_uncomposed_list { 4110 $$ = MAKE_SYNTAX (composed_markup_list, 4111 @2, $1, $2); 4112 } 4113 ; 4114 4115markup_braced_list: 4116 '{' markup_braced_list_body '}' { 4117 $$ = scm_reverse_x ($2, SCM_EOL); 4118 } 4119 ; 4120 4121markup_braced_list_body: 4122 /* empty */ { $$ = SCM_EOL; } 4123 | markup_braced_list_body markup { 4124 $$ = scm_cons ($2, $1); 4125 } 4126 | markup_braced_list_body markup_list { 4127 $$ = Srfi_1::append_reverse ($2, $1); 4128 } 4129 ; 4130 4131markup_command_list: 4132 MARKUP_LIST_FUNCTION markup_command_list_arguments { 4133 $$ = scm_cons ($1, scm_reverse_x ($2, SCM_EOL)); 4134 } 4135 ; 4136 4137markup_command_embedded_lilypond: 4138 '{' { 4139 parser->lexer_->push_note_state (); 4140 } embedded_lilypond '}' { 4141 parser->lexer_->pop_state (); 4142 $$ = $3; 4143 } 4144 ; 4145 4146 4147markup_command_basic_arguments: 4148 EXPECT_MARKUP_LIST markup_command_list_arguments markup_list { 4149 $$ = scm_cons ($3, $2); 4150 } 4151 | EXPECT_SCM markup_command_list_arguments embedded_scm { 4152 $$ = check_scheme_arg (parser, @3, $3, $2, $1); 4153 } 4154 | EXPECT_SCM markup_command_list_arguments markup_command_embedded_lilypond 4155 { 4156 $$ = check_scheme_arg (parser, @3, $3, $2, $1); 4157 } 4158 | EXPECT_SCM markup_command_list_arguments mode_changed_music { 4159 $$ = check_scheme_arg (parser, @3, $3, $2, $1); 4160 } 4161 | EXPECT_SCM markup_command_list_arguments MUSIC_IDENTIFIER { 4162 $$ = check_scheme_arg (parser, @3, $3, $2, $1); 4163 } 4164 | EXPECT_SCM markup_command_list_arguments STRING { 4165 $$ = check_scheme_arg (parser, @3, $3, $2, $1); 4166 } 4167 | EXPECT_NO_MORE_ARGS { 4168 $$ = SCM_EOL; 4169 } 4170 ; 4171 4172markup_command_list_arguments: 4173 markup_command_basic_arguments { $$ = $1; } 4174 | EXPECT_MARKUP markup_command_list_arguments markup { 4175 $$ = scm_cons ($3, $2); 4176 } 4177 ; 4178 4179markup_partial_function: 4180 MARKUP_FUNCTION markup_arglist_partial 4181 { 4182 $$ = scm_list_1 (scm_cons ($1, scm_reverse_x ($2, SCM_EOL))); 4183 } 4184 | markup_head_1_list MARKUP_FUNCTION markup_arglist_partial 4185 { 4186 $$ = scm_cons (scm_cons ($2, scm_reverse_x ($3, SCM_EOL)), 4187 $1); 4188 } 4189 ; 4190 4191markup_arglist_partial: 4192 EXPECT_MARKUP markup_arglist_partial 4193 { 4194 $$ = $2; 4195 } 4196 | EXPECT_SCM markup_arglist_partial 4197 { 4198 $$= $2; 4199 } 4200 | EXPECT_MARKUP markup_command_list_arguments 4201 { 4202 $$ = $2; 4203 } 4204 | EXPECT_SCM markup_command_list_arguments 4205 { 4206 $$ = $2; 4207 } 4208 ; 4209 4210markup_head_1_item: 4211 MARKUP_FUNCTION EXPECT_MARKUP markup_command_list_arguments { 4212 $$ = scm_cons ($1, scm_reverse_x ($3, SCM_EOL)); 4213 } 4214 ; 4215 4216markup_head_1_list: 4217 markup_head_1_item { 4218 $$ = scm_list_1 ($1); 4219 } 4220 | markup_head_1_list markup_head_1_item { 4221 $$ = scm_cons ($2, $1); 4222 } 4223 ; 4224 4225markup_word: 4226 STRING 4227 | SYMBOL 4228 ; 4229 4230simple_markup: 4231 markup_word 4232 { 4233 $$ = make_simple_markup ($1); 4234 } 4235 | simple_markup_noword 4236 ; 4237 4238simple_markup_noword: 4239 SCORE { 4240 parser->lexer_->push_note_state (); 4241 } '{' score_body '}' { 4242 Score *sc = unsmob<Score> ($4); 4243 sc->origin ()->set_spot (@$); 4244 if (sc->defs_.empty ()) { 4245 Output_def *od = get_layout (parser); 4246 sc->add_output_def (od); 4247 od->unprotect (); 4248 } 4249 $$ = scm_list_2 (Lily::score_markup, $4); 4250 parser->lexer_->pop_state (); 4251 } 4252 | MARKUP_FUNCTION markup_command_basic_arguments { 4253 $$ = scm_cons ($1, scm_reverse_x ($2, SCM_EOL)); 4254 } 4255 | markup_scm MARKUP_IDENTIFIER 4256 { 4257 $$ = $2; 4258 } 4259 ; 4260 4261markup: 4262 markup_head_1_list simple_markup 4263 { 4264 $$ = scm_car (MAKE_SYNTAX (composed_markup_list, 4265 @2, $1, scm_list_1 ($2))); 4266 } 4267 | simple_markup { 4268 $$ = $1; 4269 } 4270 ; 4271 4272%% 4273 4274void 4275Lily_parser::set_yydebug (bool x) 4276{ 4277 yydebug = x; 4278} 4279 4280SCM 4281Lily_parser::do_yyparse () 4282{ 4283 return scm_c_with_fluid (Lily::f_parser, 4284 self_scm (), 4285 do_yyparse_trampoline, 4286 static_cast <void *>(this)); 4287} 4288 4289SCM 4290Lily_parser::do_yyparse_trampoline (void *parser) 4291{ 4292 SCM retval = SCM_UNDEFINED; 4293 yyparse (static_cast <Lily_parser *>(parser), &retval); 4294 return retval; 4295} 4296 4297 4298 4299/* 4300 4301It is a little strange to have this function in this file, but 4302otherwise, we have to import music classes into the lexer. 4303 4304*/ 4305int 4306Lily_lexer::try_special_identifiers (SCM *destination, SCM sid) 4307{ 4308 if (unsmob<Book> (sid)) { 4309 Book *book = unsmob<Book> (sid)->clone (); 4310 *destination = book->self_scm (); 4311 book->unprotect (); 4312 4313 return BOOK_IDENTIFIER; 4314 } else if (scm_is_number (sid)) { 4315 *destination = sid; 4316 return NUMBER_IDENTIFIER; 4317 } else if (unsmob<Context_def> (sid)) 4318 { 4319 *destination = unsmob<Context_def> (sid)->clone ()->unprotect (); 4320 return SCM_IDENTIFIER; 4321 } else if (unsmob<Context_mod> (sid)) { 4322 *destination = unsmob<Context_mod> (sid)->smobbed_copy (); 4323 return SCM_IDENTIFIER; 4324 } else if (Music *mus = unsmob<Music> (sid)) { 4325 mus = mus->clone (); 4326 *destination = mus->self_scm (); 4327 bool is_event = mus->is_mus_type ("post-event"); 4328 mus->unprotect (); 4329 return is_event ? EVENT_IDENTIFIER : MUSIC_IDENTIFIER; 4330 } else if (unsmob<Pitch> (sid)) { 4331 *destination = unsmob<Pitch> (sid)->smobbed_copy (); 4332 return PITCH_IDENTIFIER; 4333 } else if (unsmob<Duration> (sid)) { 4334 *destination = unsmob<Duration> (sid)->smobbed_copy (); 4335 return DURATION_IDENTIFIER; 4336 } else if (unsmob<Output_def> (sid)) { 4337 *destination = unsmob<Output_def> (sid)->clone ()->unprotect (); 4338 return SCM_IDENTIFIER; 4339 } else if (unsmob<Score> (sid)) { 4340 *destination = unsmob<Score> (sid)->clone ()->unprotect (); 4341 return SCM_IDENTIFIER; 4342 } else if (scm_is_pair (sid) 4343 && scm_is_pair (scm_car (sid)) 4344 && scm_is_true (Lily::key_p (scm_caar (sid)))) { 4345 *destination = sid; 4346 return LOOKUP_IDENTIFIER; 4347 } 4348 return -1; 4349} 4350 4351// check_scheme_arg checks one argument with a given predicate for use 4352// in an argument list and throws a syntax error if it is unusable. 4353// The argument is prepended to the argument list in any case. After 4354// throwing a syntax error, the argument list is terminated with #f as 4355// its last cdr in order to mark it as uncallable while not losing 4356// track of its total length. 4357// 4358// There are a few special considerations: if optional argument disp 4359// is given (otherwise it defaults to SCM_UNDEFINED), it will be used 4360// instead of arg in a prospective error message. This is useful if 4361// arg is not the actual argument but rather a transformation of it. 4362// 4363// If arg itself is SCM_UNDEFINED, the predicate is considered false 4364// and an error message using disp is produced unconditionally. 4365 4366SCM check_scheme_arg (Lily_parser *parser, Input loc, 4367 SCM arg, SCM args, SCM pred, SCM disp) 4368{ 4369 if (SCM_UNBNDP (arg)) 4370 args = scm_cons (disp, args); 4371 else { 4372 args = scm_cons (arg, args); 4373 if (scm_is_true (scm_call_1 (pred, arg))) 4374 return args; 4375 } 4376 scm_set_cdr_x (scm_last_pair (args), SCM_EOL); 4377 MAKE_SYNTAX (argument_error, loc, scm_length (args), pred, 4378 SCM_UNBNDP (disp) ? arg : disp); 4379 scm_set_cdr_x (scm_last_pair (args), SCM_BOOL_F); 4380 return args; 4381} 4382 4383SCM loc_on_copy (Lily_parser *parser, Input loc, SCM arg) 4384{ 4385 if (Music *m = unsmob<Music> (arg)) 4386 { 4387 m = m->clone (); 4388 m->set_spot (parser->lexer_->override_input (loc)); 4389 return m->unprotect (); 4390 } 4391 if (Book *b = unsmob<Book> (arg)) 4392 { 4393 b = b->clone (); 4394 b->origin ()->set_spot (parser->lexer_->override_input (loc)); 4395 return b->unprotect (); 4396 } 4397 if (Context_def *cd = unsmob<Context_def> (arg)) 4398 { 4399 cd = cd->clone (); 4400 cd->origin ()->set_spot (parser->lexer_->override_input (loc)); 4401 return cd->unprotect (); 4402 } 4403 if (Output_def *od = unsmob<Output_def> (arg)) 4404 { 4405 od = od->clone (); 4406 od->input_origin_ = parser->lexer_->override_input (loc); 4407 return od->unprotect (); 4408 } 4409 if (Score *s = unsmob<Score> (arg)) 4410 { 4411 s = s->clone (); 4412 s->origin ()->set_spot (parser->lexer_->override_input (loc)); 4413 return s->unprotect (); 4414 } 4415 if (Context_mod *cm = unsmob<Context_mod> (arg)) 4416 { 4417 return cm->smobbed_copy (); 4418 } 4419 return arg; 4420} 4421 4422SCM 4423make_reverse_key_list (SCM keys) 4424{ 4425 if (scm_is_true (Lily::key_p (keys))) 4426 return scm_list_1 (keys); 4427 if (scm_is_string (keys)) 4428 return scm_list_1 (scm_string_to_symbol (keys)); 4429 if (!ly_is_list (keys)) 4430 return SCM_UNDEFINED; 4431 SCM res = SCM_EOL; 4432 for (; scm_is_pair (keys); keys = scm_cdr (keys)) 4433 { 4434 SCM elt = scm_car (keys); 4435 if (scm_is_true (Lily::key_p (elt))) 4436 res = scm_cons (elt, res); 4437 else if (scm_is_string (elt)) 4438 res = scm_cons (scm_string_to_symbol (elt), res); 4439 else return SCM_UNDEFINED; 4440 } 4441 return res; 4442} 4443 4444SCM 4445try_string_variants (SCM pred, SCM str) 4446{ 4447 // a matching predicate is always ok 4448 if (scm_is_true (scm_call_1 (pred, str))) 4449 return str; 4450 // a key may be interpreted as a list of keys if it helps 4451 if (scm_is_true (Lily::key_p (str))) { 4452 str = scm_list_1 (str); 4453 if (scm_is_true (scm_call_1 (pred, str))) 4454 return str; 4455 return SCM_UNDEFINED; 4456 } 4457 4458 if (!scm_is_string (str)) 4459 return SCM_UNDEFINED; 4460 4461 // Let's attempt the symbol list interpretation first. 4462 4463 str = scm_string_to_symbol (str); 4464 4465 SCM lst = scm_list_1 (str); 4466 4467 if (scm_is_true (scm_call_1 (pred, lst))) 4468 return lst; 4469 4470 // Try the single symbol interpretation 4471 4472 if (scm_is_true (scm_call_1 (pred, str))) 4473 return str; 4474 4475 return SCM_UNDEFINED; 4476} 4477 4478SCM 4479try_word_variants (SCM pred, SCM str) 4480{ 4481 // str is always a string when we come here 4482 4483 if (scm_is_true (scm_call_1 (pred, str))) 4484 return str; 4485 4486 // If this cannot be a string representation of a symbol list, 4487 // we are through. 4488 4489 if (!is_regular_identifier (str, true)) 4490 return SCM_UNDEFINED; 4491 4492 str = scm_string_split (str, SCM_MAKE_CHAR ('.')); 4493 for (SCM &p : as_ly_scm_list (str)) 4494 p = scm_string_split (p, SCM_MAKE_CHAR (',')); 4495 str = scm_append_x (str); 4496 for (SCM &p : as_ly_scm_list (str)) 4497 p = scm_string_to_symbol (p); 4498 4499 // Let's attempt the symbol list interpretation first. 4500 4501 if (scm_is_true (scm_call_1 (pred, str))) 4502 return str; 4503 4504 // If there is just one symbol in the list, we might interpret 4505 // it as a single symbol 4506 4507 if (scm_is_null (scm_cdr (str))) 4508 { 4509 str = scm_car (str); 4510 if (scm_is_true (scm_call_1 (pred, str))) 4511 return str; 4512 } 4513 4514 return SCM_UNDEFINED; 4515} 4516 4517bool 4518is_regular_identifier (SCM id, bool multiple) 4519{ 4520 if (!scm_is_string (id)) 4521 return false; 4522 4523 string str = ly_scm2string (id); 4524 4525 bool middle = false; 4526 4527 for (string::iterator it=str.begin(); it != str.end (); it++) 4528 { 4529 int c = *it & 0xff; 4530 if ((c >= 'a' && c <= 'z') 4531 || (c >= 'A' && c <= 'Z') 4532 || c > 0x7f) 4533 middle = true; 4534 else if (middle && (c == '-' || c == '_' || (multiple && 4535 (c == '.' || c == ',')))) 4536 middle = false; 4537 else 4538 return false; 4539 } 4540 return middle; 4541} 4542 4543SCM 4544make_music_from_simple (Lily_parser *parser, Input loc, SCM simple) 4545{ 4546 if (unsmob<Music> (simple)) 4547 return simple; 4548 4549 if (scm_is_symbol (simple)) 4550 { 4551 SCM out = SCM_UNDEFINED; 4552 switch (parser->lexer_->scan_word (out, simple)) 4553 { 4554 case DRUM_PITCH: 4555 { 4556 Music *n = MY_MAKE_MUSIC ("NoteEvent", loc); 4557 set_property (n, "duration", parser->default_duration_.smobbed_copy ()); 4558 set_property (n, "drum-type", out); 4559 return n->unprotect (); 4560 } 4561 case NOTENAME_PITCH: 4562 case TONICNAME_PITCH: 4563 // Take the parsed pitch 4564 simple = out; 4565 break; 4566 // Don't scan CHORD_MODIFIER etc. 4567 } 4568 } 4569 4570 if (parser->lexer_->is_note_state ()) { 4571 if (unsmob<Pitch> (simple)) { 4572 Music *n = MY_MAKE_MUSIC ("NoteEvent", loc); 4573 set_property (n, "duration", parser->default_duration_.smobbed_copy ()); 4574 set_property (n, "pitch", simple); 4575 return n->unprotect (); 4576 } 4577 SCM d = simple; 4578 if (scm_is_integer (simple)) 4579 d = make_duration (simple); 4580 if (unsmob<Duration> (d)) { 4581 Music *n = MY_MAKE_MUSIC ("NoteEvent", loc); 4582 set_property (n, "duration", d); 4583 return n->unprotect (); 4584 } 4585 return simple; 4586 } else if (parser->lexer_->is_lyric_state ()) { 4587 if (Text_interface::is_markup (simple)) 4588 return MAKE_SYNTAX (lyric_event, loc, simple, 4589 parser->default_duration_.smobbed_copy ()); 4590 } else if (parser->lexer_->is_chord_state ()) { 4591 if (unsmob<Pitch> (simple)) 4592 return MAKE_SYNTAX 4593 (event_chord, 4594 loc, 4595 make_chord_elements (loc, simple, 4596 parser->default_duration_.smobbed_copy (), 4597 SCM_EOL)); 4598 } 4599 return simple; 4600} 4601 4602Music * 4603make_music_with_input (SCM name, Input where) 4604{ 4605 Music *m = make_music_by_name (name); 4606 m->set_spot (where); 4607 return m; 4608} 4609 4610SCM 4611make_simple_markup (SCM a) 4612{ 4613 return a; 4614} 4615 4616SCM 4617make_duration (SCM d, int dots, SCM factor) 4618{ 4619 Duration k; 4620 4621 if (Duration *dur = unsmob<Duration> (d)) { 4622 if (!dots && SCM_UNBNDP (factor)) 4623 return d; 4624 k = *dur; 4625 if (dots) 4626 k = Duration (k.duration_log (), k.dot_count () + dots) 4627 .compressed (k.factor ()); 4628 } else { 4629 int t = scm_to_int (d); 4630 if (t > 0 && (t & (t-1)) == 0) 4631 k = Duration (intlog2 (t), dots); 4632 else 4633 return SCM_UNDEFINED; 4634 } 4635 4636 if (!SCM_UNBNDP (factor)) 4637 k = k.compressed (from_scm<Rational> (factor)); 4638 4639 return k.smobbed_copy (); 4640} 4641 4642SCM 4643make_chord_step (SCM step_scm, Rational alter) 4644{ 4645 Pitch m (0, scm_to_int (step_scm) - 1, alter); 4646 4647 // Notename/octave are normalized 4648 if (m.get_notename () == 6) 4649 m = m.transposed (Pitch (0, 0, FLAT_ALTERATION)); 4650 4651 return m.smobbed_copy (); 4652} 4653 4654 4655SCM 4656make_chord_elements (Input loc, SCM pitch, SCM dur, SCM modification_list) 4657{ 4658 SCM res = Lily::construct_chord_elements (pitch, dur, modification_list); 4659 for (SCM s = res; scm_is_pair (s); s = scm_cdr (s)) 4660 { 4661 unsmob<Music> (scm_car (s))->set_spot (loc); 4662 } 4663 return res; 4664} 4665 4666// Return true if there are post events unaccounted for 4667bool 4668add_post_events (Music *m, SCM events) 4669{ 4670 if (!scm_is_pair (events)) 4671 return false; // successfully added -- nothing 4672 4673 while (m) { 4674 if (m->is_mus_type ("rhythmic-event")) { 4675 set_property 4676 (m, "articulations", 4677 scm_append_x (scm_list_2 4678 (get_property (m, "articulations"), 4679 events))); 4680 return false; 4681 } 4682 if (m->is_mus_type ("event-chord")) { 4683 set_property 4684 (m, "elements", 4685 scm_append_x (scm_list_2 4686 (get_property (m, "elements"), 4687 events))); 4688 return false; 4689 } 4690 if (m->is_mus_type ("sequential-music")) { 4691 SCM lp = scm_last_pair (get_property (m, "elements")); 4692 if (scm_is_pair (lp)) { 4693 m = unsmob<Music> (scm_car (lp)); 4694 continue; 4695 } 4696 return true; 4697 } 4698 if (m->is_mus_type ("music-wrapper-music") 4699 || m->is_mus_type ("time-scaled-music")) { 4700 m = unsmob<Music> (get_property (m, "element")); 4701 continue; 4702 } 4703 break; 4704 } 4705 return true; 4706} 4707 4708// Returns either a list or a post-event 4709// 4710// If PRESERVE is true, unattachable post-events are not thrown away 4711// but rather added attached to empty chords. If COMPRESS is true, a 4712// sequence consisting only of post-events may be returned as a single 4713// post-event. 4714SCM reverse_music_list (Lily_parser *parser, Input loc, SCM lst, bool preserve, bool compress) 4715{ 4716 SCM res = SCM_EOL; // Resulting reversed list 4717 SCM bad = SCM_EOL; // Bad post events 4718 SCM post = SCM_EOL; // current unattached events 4719 for (; scm_is_pair (lst); lst = scm_cdr (lst)) { 4720 SCM elt = scm_car (lst); 4721 Music *m = unsmob<Music> (elt); 4722 assert (m); 4723 if (m->is_mus_type ("post-event")) { 4724 post = post_event_cons (elt, post); 4725 continue; 4726 } 4727 if (add_post_events (m, post)) { 4728 bad = scm_cons (scm_car (post), bad); 4729 if (preserve) { 4730 Music *p = unsmob<Music> (scm_car (post)); 4731 res = scm_cons (MAKE_SYNTAX (event_chord, 4732 *p->origin (), 4733 post), 4734 res); 4735 } 4736 } 4737 post = SCM_EOL; 4738 res = scm_cons (elt, res); 4739 } 4740 if (scm_is_pair (post)) { 4741 if (scm_is_null (res) && compress) { // pure postevent list 4742 if (scm_is_null (scm_cdr (post))) 4743 return scm_car (post); 4744 Music *m = MY_MAKE_MUSIC ("PostEvents", loc); 4745 set_property (m, "elements", post); 4746 return m->unprotect (); 4747 } 4748 bad = ly_append2 (post, bad); 4749 if (preserve) { 4750 Music *p = unsmob<Music> (scm_car (post)); 4751 res = scm_cons (MAKE_SYNTAX (event_chord, 4752 *p->origin (), 4753 post), 4754 res); 4755 } 4756 } 4757 for (; scm_is_pair (bad); bad = scm_cdr (bad)) 4758 { 4759 Music *what = unsmob<Music> (scm_car (bad)); 4760 if (preserve) 4761 what->warning (_f ("Unattached %s", what->name ())); 4762 else 4763 what->warning (_f ("Dropping unattachable %s", what->name ())); 4764 } 4765 return res; 4766} 4767 4768SCM post_event_cons (SCM post_event, SCM tail) 4769{ 4770 Music *ev = unsmob<Music> (post_event); 4771 if (!ev) 4772 return tail; 4773 if (!ev->is_mus_type ("post-event-wrapper")) 4774 return scm_cons (post_event, tail); 4775 SCM elts = SCM_UNDEFINED; 4776 SCM props = SCM_EOL; 4777 SCM tweaks = SCM_UNDEFINED; 4778 for (SCM p = ev->get_property_alist (true); 4779 scm_is_pair (p); 4780 p = scm_cdr (p)) 4781 { 4782 SCM pair = scm_car (p); 4783 SCM sym = scm_car (pair); 4784 if (scm_is_eq (sym, ly_symbol2scm ("origin"))) 4785 continue; 4786 else if (scm_is_eq (sym, ly_symbol2scm ("elements")) 4787 && SCM_UNBNDP (elts)) 4788 elts = scm_cdr (pair); 4789 else if (scm_is_eq (sym, ly_symbol2scm ("tweaks")) 4790 && SCM_UNBNDP (tweaks)) 4791 tweaks = scm_cdr (pair); 4792 else 4793 props = scm_cons (pair, props); 4794 } 4795 if (!scm_is_pair (elts)) 4796 return tail; 4797 elts = scm_reverse_x (elts, SCM_EOL); 4798 for (SCM p = elts; scm_is_pair (p); p = scm_cdr (p)) 4799 { 4800 Music *ev = unsmob<Music> (scm_car (p)); 4801 // tweaks are always collected in-order, newer tweaks 4802 // nearer to the front of the list 4803 if (scm_is_pair (tweaks)) 4804 set_property (ev, 4805 "tweaks", 4806 Srfi_1::append_reverse (tweaks, 4807 get_property (ev, "tweaks"))); 4808 // other properties are applied last to first so that 4809 // in case of duplicate properties, the actually 4810 // current one survives 4811 for (SCM q = props; scm_is_pair (q); q = scm_cdr (q)) 4812 set_property (ev, scm_caar (q), scm_cdar (q)); 4813 } 4814 return ly_append2 (elts, tail); 4815} 4816 4817int 4818yylex (YYSTYPE *s, YYLTYPE *loc, Lily_parser *parser) 4819{ 4820 Lily_lexer *lex = parser->lexer_; 4821 4822 lex->lexval_ = s; 4823 lex->lexloc_ = loc; 4824 int tok = lex->pop_extra_token (); 4825 if (tok >= 0) 4826 return tok; 4827 lex->prepare_for_next_token (); 4828 return lex->yylex (); 4829} 4830