%{ // -*-Fundamental-*- /* adapted from parser.yy -- Bison/C++ parser for lilypond source file of the GNU LilyPond music typesetter (c) 1997--2001 Han-Wen Nienhuys Jan Nieuwenhuizen adapted for lilyfront (c) Richard Shann 2003 The result of parsing is a GList starting at lily_file The data elements of the GList are node* where node is a structure with type, user_string and a union. Each node in the list represents the result of some rule below, with the user_string containing the part of the input file that parsed to that node. The nodes are a simple list except 1) assignment statements where the assignee is a separate list entered in a symbol table. 2) SIMULTANEOUS blocks which are nodes pointing to a list for their contents 3) \score blocks which are nodes pointing to a list for their contents After parsing the function create_score() is run on each score block. This creates a staff structure for each \context Staff encountered. The staff->measures field is pointed to the start of the block enclosed by the \context Staff. This block is traversed and the durations calculated to break the list into measures which are linked into the staff->measures list. After editing graphically denemo stype the whole list is traversed writing out the user_string fields or (where they are NULL) re-creating them from the data in the DenemoObject concerned. Note that the structure node is arranged to have the same first fields as DenemoObject so that either type can appear in the parse tree. */ #define YYDEBUG 1 #define YYPRINT fprintf //#define DEBUG 1 #define YYTOKEN_TABLE 1 #include /*for memcpy */ #include /* for system() */ #include #include "view.h" /* this includes many others - many are not protected against double inclusion */ #include "chordops.h" #include "objops.h" #include "twoints.h" #include "processstaffname.h" #include "tupletops.h" #include "graceops.h" #include #include "lyparserfuncs.h" void lyrestart( FILE *new_file ); extern int lylineno; static int parser_error_linenum = 0; static gchar *parser_error_message = NULL; /* NULL for no parse error */ nodemin endcontextnode={endcontext,NULL}; /*the only instantiation of this node, used as a marker */ #define stradd(m,n) if(n.user_string){m.user_string = \ g_strconcat(m.user_string,n.user_string, NULL);} #define LATER_MESSAGE(line) \ call_parser_error("later at %d\n", __LINE__, line);return EOF static GtkWidget *parser_error_dialog; static int error_level_; /* lexer states FIXME */ void push_note_state(void); void push_figuredbass_state(void); void push_chord_state(void); void push_lyric_state(void); void pop_state(void); gboolean note_state_b(void); int lylex(void); static void lyerror(char *); static void call_parser_error(gchar *text, int lineno, int input_line_number) { g_print("The parser needs finishing a lyparser.y:%d for this idiom" " to be usable\nThe problem occured at line number %d of the" " lily input", lineno, input_line_number); parser_error("Edit or comment out the offending idiom if possible\n", input_line_number); } static GList *lily_file = NULL; /* the entire data generated by the parse */ /* before EOF there may be white space which won't * be collected by any rule - the lexer passes it * using set_trailing_white_space() */ static gchar *trailing_white_space = NULL; GHashTable* name_value_pairs=NULL; GHashTable* scm_identifiers=NULL; #if 0 #define MALLOC_NODE(n, a) nodegeneric*n = \ (nodegeneric*)g_malloc0(sizeof(nodegeneric));\ memcpy(n, &a, sizeof(a)); #else #define MALLOC_NODE(n, a) nodegeneric*n = \ (nodegeneric*)g_malloc0(sizeof(nodegeneric));\ n->type=a.type;n->user_string = a.user_string; #endif static void set_identifier (char* name, nodeglist *value) { if(!name_value_pairs) name_value_pairs = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (name_value_pairs, (gpointer)name, (gpointer)value); #if DEBUG //g_warning("Set identifier %s to value %p\n",name, value); g_print("Set identifier %s to value %s\n",name, u_str(value->branch)); #endif } static nodeglist * typed_glist (GList *g, guint t) { nodeglist *nodeg = (nodeglist *)g_malloc0(sizeof(nodeglist)); nodeg->type = t; nodeg->branch = g; return nodeg; } #ifdef YYPRINT static gchar * type_name(gint type); #endif gboolean regular_identifier_b (char *s) { gboolean v = TRUE; while (*s && v) { v = v && isalpha (*s); s++; } return v; } static int intlog2(int t) { int i=1, n=0; while ( (i<0;enshift--) ret = g_strconcat(ret,"is",NULL); for(;enshift<0;enshift++) ret = g_strconcat(ret,"es",NULL);/*tricksy - only one happens */ return ret; } // needed for bison.simple's malloc () and free () #include #include #include #define YYERROR_VERBOSE 1 static void lyerror(char *s) { parser_error(s, lylineno); } %} /* We use SCMs to do strings, because it saves us the trouble of deleting them. Let's hope that a stack overflow doesnt trigger a move of the parse stack onto the heap. */ %{ %} %union { nodemin minimal; nodegeneric generic; nodec c; nodei i; node2i t; node4i f; nodeb b; noden n; nodeid id; nodegstr gstr; nodemus music; noder r; nodeglist *branch; GList *scm; } /* denemo special tokens */ %token DENEMO_MEASURES /* make a distinction for initial and other clef changes etc for denemo which would otherwise issue a change of clef etc at the start of each staff */ %token TEXT %token staffcontext voicecontext lyricscontext figuredbasscontext %token endcontext %token MUSICMODE %token TONEOPTION %token DYNAMICMARK /* tokens which are not keywords */ %token AUTOCHANGE %token ALIAS %token APPLY %token ARPEGGIO %token DYNAMICSCRIPT %token ACCEPTS %token ALTERNATIVE %token BAR %token BREAK %token BREATHE %token CHORDMODIFIERS %token CHORDS %token CHAR_T %token CLEF_ %token CM_T %token CONSISTS %token SEQUENTIAL %token SIMULTANEOUS %token GROBDESCRIPTIONS %token CONSISTSEND %token DENIES %token DURATION %token EXTENDER %token FIGURES FIGURE_OPEN FIGURE_CLOSE %token FIGURE_BRACKET_CLOSE FIGURE_BRACKET_OPEN %token GLISSANDO %token GRACE %token HEADER %token HYPHEN %token IN_T %token INVALID %token KEY %token LYRICS %token MARK %token MARKUP %token MULTI_MEASURE_REST %token MIDI %token MM_T %token PITCH %token DEFAULT %token NAME %token PITCHNAMES %token NOTES %token PAPER %token PARTIAL_ %token PENALTY %token PROPERTY %token OVERRIDE SET REVERT %token PT_T %token RELATIVE %token REMOVE %token REPEAT %token ADDLYRICS %token PARTCOMBINE %token SCORE %token SCRIPT %token SKIP %token SPANREQUEST %token STYLESHEET %token COMMANDSPANREQUEST %token TEMPO %token OUTPUTPROPERTY %token TIME_T %token TIMES %token TRANSLATOR %token TRANSPOSE %token TYPE %token UNSET %token CONTEXT %token LAYOUT %token LYRICSTO %token LYRICMODE %token NEWCONTEXT %token LILYVERSION %token DRUM_PITCH %token MUSIC_FUNCTION %token REST %token DOUBLE_ANGLE_CLOSE ">>" %token DOUBLE_ANGLE_OPEN "<<" /* escaped */ %token E_CHAR E_EXCLAMATION E_SMALLER E_BIGGER E_OPEN E_CLOSE %token E_LEFTSQUARE E_RIGHTSQUARE E_TILDE %token E_BACKSLASH %token CHORD_BASS CHORD_COLON CHORD_MINUS CHORD_CARET %token FIGURE_SPACE %type exclamations questions dots optional_rest %type bass_number bass_mod %type br_bass_figure bass_figure figure_list figure_spec %token '=' %token '{' %token '<' %token '}' %token '>' %token '|' %token '/' %token '*' %token '(' %token ')' %token '~' %token '[' %token ']' //%token ">>" //%token "<<" %token '.' %token '?' %token '!' %token '\'' %token ',' %token DIGIT %token NOTENAME_PITCH %token TONICNAME_PITCH %token CHORDMODIFIER_PITCH %token DURATION_IDENTIFIER %token FRACTION %token IDENTIFIER %token SCORE_IDENTIFIER %token MUSIC_OUTPUT_DEF_IDENTIFIER %token NUMBER_IDENTIFIER %token REQUEST_IDENTIFIER %token MUSIC_IDENTIFIER TRANSLATOR_IDENTIFIER %token STRING_IDENTIFIER %token SCM_IDENTIFIER %token RESTNAME %token SKIPNAME %token STRING_ %token SCM_T %token UNSIGNED %token REAL %type output_def %type lilypond_header lilypond_header_body toplevel_expression assignment score_block %type direction_less_char direction_less_event direction_reqd_event %type sub_quotes sup_quotes %type simple_element event_chord command_element Simple_music Composite_music %type chord_body %type chord_body_element %type music_function_chord_body %type chord_body_elements %type Repeated_music %type Alternative_music %type tremolo_type %type bare_int bare_unsigned %type script_dir %type octave_check %type identifier_init %type steno_duration %type optional_notemode_duration multiplied_duration %type verbose_duration %type post_events %type note_chord_element %type gen_text_def %type full_markup %type steno_pitch pitch absolute_pitch %type explicit_pitch steno_tonic_pitch %type chord_additions chord_subtractions chord_notes chord_step %type chord %type chord_note chord_inversion chord_bass %type duration_length %type fraction %type embedded_scm scalar %type Music Sequential_music Simultaneous_music %type relative_music re_rhythmed_music part_combined_music %type property_def translator_change %type Music_list %type music_output_def_body %type shorthand_command_req %type post_event %type command_req verbose_command_req %type extender_req %type hyphen_req %type string %type bare_number number_expression number_term number_factor %type score_body %type translator_spec_block translator_spec_body %type tempo_event tempo_optional %type notenames_body notenames_block chordmodifiers_block %type script_abbreviation %left '-' '+' /* We don't assign precedence to / and *, because we might need varied prec levels in different prods */ %left UNARY_MINUS %% lilypond: /* empty */ | lilypond toplevel_expression { if(lily_file) { lily_file = g_list_concat (lily_file, $2); list_tree("In parser toplevel", lily_file); } else { lily_file = $2; } } | lilypond assignment { if(lily_file) { lily_file= g_list_concat(lily_file, $2); } else { lily_file = $2; } } | lilypond error { error_level_ = 1; } | lilypond INVALID { error_level_ = 1; } ; toplevel_expression: notenames_block { /* this is the \pitchnames thing in the include files - we will perhaps leave this out for now - see below for where the include file is parsed for the pitchname table - we have to recognize at least one set of pitchnames of course ...*/ $$ = g_list_append(NULL, $1); /* creates a new mudelaobj structure comprising the token TEXT, and the Gstring pointed to by input_text, which is reset to NULL. We ignore the value of notename_block since we don't interpret it further */ } | chordmodifiers_block { $$ = $1; } | lilypond_header { $$ = $1; } | score_block { $$ = $1;/* add this score to the root data list lily_file */ } | output_def { $$ = $1; } | embedded_scm { $$ = $1; } ; embedded_scm: SCM_T { MALLOC_NODE(n, $1); $$ = g_list_append(NULL,n); } | SCM_IDENTIFIER { MALLOC_NODE(n, $1); ((nodegstr*)n)->gstr = $1.gstr; $$ = g_list_append(NULL, n); } ; chordmodifiers_block: CHORDMODIFIERS notenames_body { $$ = $2; /* intercept this at lexical level*/ } ; notenames_block: PITCHNAMES notenames_body { $$ = $2; } ; notenames_body: embedded_scm { $$ = $1; } ; lilypond_header_body: { $$ = NULL; } | lilypond_header_body assignment { if($1) { $$ = g_list_concat($1, $2); } else $$ = $2; } ; lilypond_header: HEADER '{' lilypond_header_body '}' { MALLOC_NODE(n1, $1); MALLOC_NODE(n4, $4); n1->user_string = g_strconcat($1.user_string, $2.user_string, NULL); $$ = g_list_append(NULL,n1); $$ = g_list_concat($$,$3); $$ = g_list_append($$, n4); } | LILYVERSION STRING_ { MALLOC_NODE(n,$1); g_free(n->user_string); n->user_string = $2.gstr->str; set_identifier("lilyversion", typed_glist (g_list_append(NULL,n), STRING_IDENTIFIER)); $$ = NULL; } ; /* DECLARATIONS */ assignment: STRING_ '=' identifier_init { GList *ret; MALLOC_NODE (n1, $1); MALLOC_NODE (n2, $2); if (! regular_identifier_b ($1.gstr->str)) { g_warning (_("Identifier should have alphabetic characters" " only please")); } #if DEBUG g_print("got to assignment with %s %s ",$1.gstr->str, $2.user_string); if ($3->type == STRING_IDENTIFIER) g_print("%s\n", u_str($3->branch)); else if ($3->type == MUSIC_IDENTIFIER) g_print("%s\n", "some music"); else g_print("type %d\n", $3->type); #endif /* $3 because mid rule action deleted */ set_identifier ($1.gstr->str, $3); ((nodeglist*)n2)->branch = $3->branch; ret = g_list_append(NULL, n2); $$ = g_list_prepend(ret, n1); /* TODO: devise standard for protection in parser. The parser stack lives on the C-stack, which means that all objects can be unprotected as soon as they're here. */ } ; identifier_init: score_block { /* I don't think this can ever get used, once defined! */ $$ = typed_glist ($1, SCORE_IDENTIFIER); } | output_def { $$ = typed_glist ($1, MUSIC_OUTPUT_DEF_IDENTIFIER); } | translator_spec_block { $$ = typed_glist (g_list_append(NULL,$1), TRANSLATOR_IDENTIFIER); } | Music { $$ = typed_glist ($1, MUSIC_IDENTIFIER); } | post_event { $$ = typed_glist ($1, REQUEST_IDENTIFIER); } | verbose_duration { MALLOC_NODE(n,$1); $$ = typed_glist (g_list_append(NULL,n), DURATION_IDENTIFIER); } | number_expression { $$ = typed_glist ($1, STRING_IDENTIFIER); } | string { nodegeneric x; x.type = STRING_IDENTIFIER; x.user_string = strdup($1.gstr->str); MALLOC_NODE(n,x); $$ = typed_glist (g_list_append(NULL,n), STRING_IDENTIFIER); } | embedded_scm { $$ = typed_glist ($1, SCM_IDENTIFIER); } ; translator_spec_block: TRANSLATOR '{' translator_spec_body '}' { $$ = $3; } ; translator_spec_body: TRANSLATOR_IDENTIFIER { } ; /* SCORE */ score_block: SCORE '{' score_body '}' { MALLOC_NODE(n,$1); n->user_string = g_strconcat($1.user_string, "{" , NULL); /*FIXME memory leak of $1,2 */ ((nodeglist*)n)->post_user_string = "}"; ((nodeglist*)n)->branch = $3; $$ = g_list_append(NULL, n); } ; score_body: Music { $$ = $1; } | SCORE_IDENTIFIER { $$ = g_list_append(NULL, $1.id); } | score_body lilypond_header { lyerror ("parser should have caught this"); /*intercept this at lexical level*/ } | score_body output_def { lyerror ("parser should have caught this"); /*intercept this at lexical level*/ } | score_body error { lyerror("score_body error"); } ; /* MIDI */ output_def: music_output_def_body '}' { // MALLOC_NODE(n2, $2) // $$ = g_list_append($1, n2); /* THIS-> lexer_-> scopes_.pop ();*/ } ; music_output_def_body: MIDI '{' tempo_optional { // set_identifier("midi_tempo", typed_glist ($3, STRING_IDENTIFIER)); // $$ = $3; } | PAPER '{' { /* caught by lexer - does not occur*/ lyerror ("parser should have caught this"); } | LAYOUT '{' { /* caught by lexer - does not occur*/ lyerror ("parser should have caught this"); } | music_output_def_body error { lyerror("music_output_def_body error"); } ; tempo_optional: /* empty */ { $$ = NULL; } | tempo_event { $$ = $1; } ; tempo_event: TEMPO steno_duration '=' bare_unsigned { MALLOC_NODE(n, $4); ((nodei*)n)->i = $4.i; $$ = g_list_append(NULL, n); } ; /* The representation of a list is the (LIST . LAST-CONS) to have efficient append. */ Music_list: /* empty */ { $$ = NULL; } | Music_list Music { if($1) { #if DEBUG g_print("building up a music list now from %s to %s\n", u_str($1), u_str($2)); #endif $$ = g_list_concat($1, $2); } else $$ = $2; } /* | Music_list embedded_scm { } */ | Music_list error { } ; Music: Simple_music | Composite_music { $$ = $1; } ; Alternative_music: /* empty */ { $$ = NULL; } | ALTERNATIVE '{' Music_list '}' { GList* ret; MALLOC_NODE(n1, $1); MALLOC_NODE(n4, $4); stradd($1, $2); ret = g_list_append(NULL, n1); ret = g_list_concat(ret, $3); $$ = g_list_append(ret, n4); } ; Repeated_music: REPEAT string bare_unsigned Music Alternative_music { GList* ret; MALLOC_NODE(n1, $1); stradd($1, $2); stradd($1, $3); ret = g_list_append(NULL, n1); ret = g_list_concat(ret, $4); if($5) ret = g_list_concat(ret, $5); $$ = ret; #if 0 $$ = new_data_el (REPEAT,); FINISH THIS $$ = g_list_append ($$, new_data_el (STRINGL)....need to have the input strings for each token available - use a struct in yylval. #endif } ; Sequential_music: SEQUENTIAL '{' Music_list '}' { MALLOC_NODE(n1, $1); n1->user_string = g_strconcat($1.user_string, "{", NULL); /*FIXME memory leak $1,2 and $4*/ ((nodeglist*)n1)->post_user_string = "}" ; ((nodeglist*)n1)->branch = $3; $$ = g_list_prepend(NULL, n1); } | '{' Music_list '}' { MALLOC_NODE(n1, $1); n1->user_string = "{"; ((nodeglist*)n1)->post_user_string = "}"; /* FIXME memory leak of $3 */ ((nodeglist*)n1)->type = SEQUENTIAL; ((nodeglist*)n1)->branch = $2; g_print("user string %s\n", u_str($2)); $$ = g_list_prepend(NULL, n1); } ; Simultaneous_music: SIMULTANEOUS '{' Music_list '}'{ LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = new Simultaneous_music (SCM_EOL); $$->set_mus_property ("elements", ly_car ($3)); $$->set_spot(THIS->here_input()); #endif } | simul_open Music_list simul_close { /* we don't try to disambiguate chords on one stave from notes one to a staff here that is done in generate_chords() called by create_score() */ // RRR MALLOC_NODE(n1, $2); nodegeneric*n1 = (nodegeneric*)g_malloc0(sizeof(nodegeneric)); n1->user_string = "<<"; ((nodeglist*)n1)->post_user_string = ">>"; /* FIXME memory leak of $3 */ ((nodeglist*)n1)->type = SIMULTANEOUS; ((nodeglist*)n1)->branch = $2; $$ = g_list_prepend(NULL, n1); } ; Simple_music: event_chord { $$ = $1; } | OUTPUTPROPERTY embedded_scm embedded_scm '=' embedded_scm { LATER_MESSAGE(@$.first_line); #ifdef LATER SCM pred = $2; if (!gh_symbol_p ($3)) { THIS->parser_error (_ ("Second argument must be a symbol")); } /* Should check # args */ if (!gh_procedure_p (pred)) { THIS->parser_error (_ ("First argument must be a procedure" " taking one argument")); } Music *m = new Music (SCM_EOL); m->set_mus_property ("predicate", pred); m->set_mus_property ("grob-property", $3); m->set_mus_property ("grob-value", $5); m->set_mus_property ("iterator-ctor", Output_property_music_iterator::constructor_cxx_function); $$ = m; #endif } | MUSIC_IDENTIFIER { /* this may be ok now ... */ /* has to be big enough for DenemoObject access eg when writing start_ticks in break into measures... */ nodeid *n = (nodeid*)g_malloc0(sizeof(nodegeneric)); n->type = $1.type; n->user_string = $1.user_string; n->id = $1.id; $$ = g_list_append(NULL, n); } | property_def { $$ = $1; /* FIXME - we really don't want to put all these nodes into the music, as denemo will have to go over them - amalgamate the strings into a TEXT node */ } | translator_change { LATER_MESSAGE(@$.first_line); } ; Composite_music: CONTEXT STRING_ Music { MALLOC_NODE (n1, $1); if(!strcmp("Staff",$2.gstr->str)) n1->type = staffcontext; else if(!strcmp("Voice",$2.gstr->str)) n1->type = voicecontext; else if(!strcmp("Lyrics",$2.gstr->str)) n1->type = lyricscontext; else if(!strcmp("FiguredBass",$2.gstr->str)) n1->type = figuredbasscontext; else n1->type = TEXT;/*ignore other contexts at present */ n1->user_string = g_strconcat($1.user_string, $2.user_string, NULL); if (n1->type == TEXT) $$ = g_list_prepend($3, n1); else $$ = g_list_append(g_list_prepend($3, n1), &endcontextnode); /* FIXME memory leak of $2 */ } | AUTOCHANGE STRING_ Music { LATER_MESSAGE(@$.first_line); #ifdef LATER Music * chm = new Music_wrapper (SCM_EOL); chm->set_mus_property ("element", $3); chm->set_mus_property ("iterator-ctor", Auto_change_iterator::constructor_cxx_function); scm_gc_unprotect_object ($3); chm->set_mus_property ("what", $2); $$ = chm; chm->set_spot (*$3->origin ()); #endif } | GRACE Music { DenemoObject *start, *end; start = newgracestart(); end = newgraceend(); start->user_string = $1.user_string; /* prevent denemo generating a "}" string this will take some effort to handle better than this hack. FIXME */ end->user_string = g_strdup(" "); $$ = g_list_append(g_list_prepend ($2,start ), end); } | CONTEXT string '=' string Music { MALLOC_NODE(n1, $1); ((nodegstr*)n1)->gstr = $4.gstr; if(!strcmp("Staff",$2.gstr->str)) n1->type = staffcontext; else if(!strcmp("Voice",$2.gstr->str)) n1->type = voicecontext; else if(!strcmp("Lyrics",$2.gstr->str)) n1->type = lyricscontext; else if(!strcmp("FiguredBass",$2.gstr->str)) n1->type = figuredbasscontext; else n1->type = TEXT;/*ignore other contexts at present */ n1->user_string = g_strconcat($1.user_string, $2.user_string, "=", $4.user_string, NULL); if (n1->type == TEXT) $$ = g_list_prepend($5, n1); else $$ = g_list_append(g_list_prepend($5, n1), &endcontextnode); /* FIXME memory leak $2 $3 $4 */ } | NEWCONTEXT STRING_ Music { MALLOC_NODE (n1, $1); if(!strcmp("Staff",$2.gstr->str)) n1->type = staffcontext; else if(!strcmp("Voice",$2.gstr->str)) n1->type = voicecontext; else if(!strcmp("Lyrics",$2.gstr->str)) { n1->type = lyricscontext; } else if(!strcmp("FiguredBass",$2.gstr->str)) n1->type = figuredbasscontext; else n1->type = TEXT;/*ignore other contexts at present */ n1->user_string = g_strconcat($1.user_string, $2.user_string, NULL); if (n1->type == TEXT) $$ = g_list_prepend($3, n1); else $$ = g_list_append(g_list_prepend($3, n1), &endcontextnode); } | TIMES fraction Music {DenemoObject *tupopen, *tupclose; tupopen = newtupopen ($2.t.a, $2.t.b); tupclose = newtupclose (); g_assert(ntype($3)==SEQUENTIAL); tupopen->user_string = g_strconcat($1.user_string, $2.user_string, u_str($3), NULL); tupclose->user_string = u_post_str($3); $$ = g_list_append(g_list_prepend (br($3), tupopen), tupclose); } | Repeated_music { $$ = $1; } | Simultaneous_music { $$ = $1; } | Sequential_music { $$ = $1; } | TRANSPOSE pitch pitch Music { /* could we try to display transposed?? later FIXME */ GList* ret; MALLOC_NODE(n1, $1); n1->user_string = g_strconcat($1.user_string, $2.user_string, $3.user_string, NULL); ret = g_list_append(NULL, n1); $$ = g_list_concat(ret, $4); } | TRANSPOSE steno_tonic_pitch Music { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = new Transposed_music (SCM_EOL); Music *p = $3; Pitch pit = *unsmob_pitch ($2); p->transpose (pit); $$->set_mus_property ("element", p); scm_gc_unprotect_object (p); #endif } | APPLY embedded_scm Music { u_str($2) = g_strconcat($1.user_string, u_str($2), NULL); $$ = g_list_concat($2, $3); } | NOTES { push_note_state (); } /* cont */ Music { MALLOC_NODE(n1, $1); $$ = g_list_prepend($3, n1); pop_state(); } | FIGURES { push_figuredbass_state (); } Music { MALLOC_NODE(n1, $1); $$ = g_list_prepend($3, n1); pop_state(); } | CHORDS { push_chord_state (); } Music { LATER_MESSAGE(@$.first_line); #ifdef LATER Music * chm = new Un_relativable_music ; chm->set_mus_property ("element", $3); scm_gc_unprotect_object ($3->self_scm()); $$ = chm; THIS->lexer_->pop_state (); #endif } | LYRICS { push_lyric_state (); } Music { LATER_MESSAGE(@$.first_line); MALLOC_NODE(n, $1) $$ = g_list_prepend($3, n); pop_state(); } | LYRICMODE { push_lyric_state (); } Music { MALLOC_NODE(n, $1) $$ = g_list_prepend($3, n); pop_state(); } | relative_music { $$ = $1; } | re_rhythmed_music { $$ = $1; } | part_combined_music { $$ = $1; } ; relative_music: RELATIVE absolute_pitch Music { MALLOC_NODE(n, $1) g_warning("\\relative not yet handled - do not edit graphically"); n->user_string = g_strconcat($1.user_string, $2.user_string, NULL); $$ = g_list_prepend($3, n); /* we have to record the pitch in the node and then use it to start relative interpretation of future CHORD nodes FIXME well, not really we have to record it in a variable akin to default_duration_ which can then be tracked to determine the semantics of future notes??? Or has Music already been interpreted when this rule is activated... */ } ; re_rhythmed_music: ADDLYRICS Music Music { MALLOC_NODE(n, $1); ((nodeglist*)n)->branch = g_list_append(g_list_append(NULL, g_list_append(NULL, $2)), g_list_append(NULL, $3)); /* ADDLYRICS is a branch containing two GLists */ $$ = g_list_append(NULL, n); } | LYRICSTO STRING_ Music { GList *g; MALLOC_NODE(n, $1); g_free(n->user_string); if (*$2.gstr->str == '\"') { GString * name = g_string_erase ($2.gstr, 0, 1); name = g_string_truncate(name, name->len - 1); n->user_string = name->str; } else n->user_string = $2.gstr->str; if (ntype ($3) == NEWCONTEXT) { g = $3; $3 = g_list_remove_link ( $3, g); g_list_free(g); } ((nodeglist*)n)->branch = $3; $$ = g_list_append(NULL, n); } ; part_combined_music: PARTCOMBINE STRING_ Music Music { LATER_MESSAGE(@$.first_line); #ifdef LATER Part_combine_music * p = new Part_combine_music (SCM_EOL); p->set_mus_property ("what", $2); p->set_mus_property ("elements", gh_list ($3,$4, SCM_UNDEFINED)); scm_gc_unprotect_object ($3); scm_gc_unprotect_object ($4); $$ = p; #endif } ; translator_change: TRANSLATOR STRING_ '=' STRING_ { LATER_MESSAGE(@$.first_line); #ifdef LATER Music * t = new Music (SCM_EOL); t->set_mus_property ("iterator-ctor", Change_iterator::constructor_cxx_function); t-> set_mus_property ("change-to-type", $2); t-> set_mus_property ("change-to-id", $4); $$ = t; $$->set_spot (THIS->here_input ()); #endif } ; property_def: PROPERTY STRING_ '.' STRING_ '=' scalar { MALLOC_NODE(n, $1) n->user_string = g_strconcat($1.user_string, $2.user_string, ".", $4.user_string, "=", u_str($6), NULL); $$ = g_list_append(NULL, n); /* FIXME memory leak*/ } | PROPERTY STRING_ '.' STRING_ UNSET { MALLOC_NODE(n, $1) n->user_string = g_strconcat($1.user_string, $2.user_string, $3.user_string, $4.user_string, $5.user_string, NULL); $$ = g_list_append(NULL, n); /* FIXME memory leak*/ } | SET STRING_ '.' STRING_ '=' embedded_scm { MALLOC_NODE(n, $1) n->user_string = g_strconcat($1.user_string, $2.user_string, $3.user_string, $4.user_string, $5.user_string, u_str($6), NULL); $$ = g_list_append(NULL, n); } | SET STRING_ '.' STRING_ '=' STRING_ { MALLOC_NODE(n, $1) n->user_string = g_strconcat($1.user_string, $2.user_string, $3.user_string, $4.user_string, $5.user_string, $6.user_string, NULL); $$ = g_list_append(NULL, n); } | OVERRIDE STRING_ '.' STRING_ '=' embedded_scm { MALLOC_NODE(n, $1); n->user_string = g_strconcat($1.user_string, $2.user_string, $3.user_string, $4.user_string, $5.user_string, u_str($6), NULL); $$ = g_list_append(NULL, n); } | OVERRIDE STRING_ embedded_scm '=' embedded_scm { MALLOC_NODE(n, $1); n->user_string = g_strconcat($1.user_string, $2.user_string, u_str ($3), $4.user_string, u_str ($5), NULL); $$ = g_list_append (NULL, n); } | REVERT STRING_ embedded_scm { MALLOC_NODE(n, $1); n->user_string = g_strconcat($1.user_string, $2.user_string, u_str ($3), NULL); $$ = g_list_append (NULL, n); } | PROPERTY STRING_ '.' STRING_ REVERT embedded_scm { MALLOC_NODE(n, $1); n->user_string = g_strconcat($1.user_string, $2.user_string, $3.user_string, $4.user_string, $5.user_string, u_str ($6), NULL); $$ = g_list_append (NULL, n); } ; scalar: string { MALLOC_NODE(n, $1);$$ = g_list_append (NULL, n); /*FIXME copy value */} | bare_int { MALLOC_NODE(n, $1);$$ = g_list_append (NULL, n); /*FIXME copy value */ } | embedded_scm { $$ = $1; } ; pre_events: /* empty */ ; event_chord: pre_events simple_element post_events { /* things like start cresc, simple_element end cresc */ set_post_events ((DenemoObject *) ($2->data), u_str ($2), $3); $$ = $2;/* FIXME memory leak */ } | command_element { $$ = $1; } | note_chord_element { $$ = $1; } ; note_chord_element: chord_body optional_notemode_duration post_events { GList *firstchord = br ($1); if (firstchord && firstchord->data) changedur ((DenemoObject *)(firstchord->data), $2.t1.a, $2.t1.b); set_post_events ((DenemoObject *) ($1->data), u_str ($1), $3); $$ = $1; } ; chord_open: '<' ; chord_close: '>' ; chord_body: chord_open chord_body_elements chord_close { nodegeneric*n1 = (nodegeneric*)g_malloc0(sizeof(nodegeneric)); n1->user_string = "<"; ((nodeglist*)n1)->post_user_string = ">"; ((nodeglist*)n1)->type = SIMULTANEOUS; ((nodeglist*)n1)->branch = $2; $$ = g_list_prepend(NULL, n1); } ; chord_body_elements: /* empty */ { $$ = NULL; } | chord_body_elements chord_body_element { $$ = g_list_concat ($1, $2); } ; music_function_chord_body: MUSIC_FUNCTION { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_list_2 ($1, make_input (@$)); #endif } ; chord_body_element: pitch exclamations questions octave_check post_events { DenemoObject *mud = newchord ( 0, 0, 0); if (!note_state_b ()) lyerror (_ ("Have to be in Note mode for notes")); addtone ( mud, $1.n.mid_c_offset, $1.n.enshift, 0);/*FIXME should be using $1.n directly */ #define no ((note*)((((chord *)mud->object)->notes)->data)) if ($3.i % 2) { no->showaccidental = TRUE; ( (chord *)mud->object)->hasanacc = TRUE; } if ($2.i % 2 ) { no->showaccidental = TRUE; ( (chord *)mud->object)->hasanacc = TRUE; } #undef no mud->user_string = $1.user_string; if ($2.i) stradd ( (*mud),$2); if ($3.i) stradd ( (*mud),$3); //stradd ( (*mud),$4); set_post_events (mud, mud->user_string, $5); $$ = g_list_append (NULL,mud); } | DRUM_PITCH post_events { LATER_MESSAGE(@$.first_line); #ifdef LATER Music *n = MY_MAKE_MUSIC ("NoteEvent"); n->set_property ("duration", $2); n->set_property ("drum-type", $1); n->set_spot (@$); if (scm_is_pair ($2)) { SCM arts = scm_reverse_x ($2, SCM_EOL); n->set_property ("articulations", arts); } $$ = n; #endif // LATER } | music_function_chord_body { LATER_MESSAGE(@$.first_line); } ; command_element: command_req { $$ = $1; } | E_LEFTSQUARE { LATER_MESSAGE(@$.first_line); #ifdef LATER Span_req *l = new Span_req; l->set_span_dir (START); l->set_mus_property ("span-type", scm_makfrom0str ("ligature")); l->set_spot (THIS->here_input ()); $$ = new Request_chord (SCM_EOL); $$->set_mus_property ("elements", gh_cons (l, SCM_EOL)); scm_gc_unprotect_object (l->self_scm ()); $$->set_spot (THIS->here_input ()); #endif } | E_RIGHTSQUARE { LATER_MESSAGE(@$.first_line); #ifdef LATER Span_req *l = new Span_req; l->set_span_dir (STOP); l->set_mus_property ("span-type", scm_makfrom0str ("ligature")); l->set_spot (THIS->here_input ()); $$ = new Request_chord (SCM_EOL); $$->set_mus_property ("elements", gh_cons (l, SCM_EOL)); $$->set_spot (THIS->here_input ()); scm_gc_unprotect_object (l->self_scm ()); #endif } | E_BACKSLASH { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = new Music (gh_list (gh_cons (ly_symbol2scm ("name"), ly_symbol2scm ("separator")), SCM_UNDEFINED)); $$->set_spot (THIS->here_input ()); #endif } | '|' { MALLOC_NODE(n, $1); $$ = g_list_append(NULL, n); /* this node used to be used by denemo to split the glist into measures */ } | BAR STRING_ { MALLOC_NODE(n, $1); n->user_string = g_strconcat($1.user_string, $2.user_string, NULL);/* FIXME memory leaks */ $$ = g_list_append(NULL, n); } | PARTIAL_ duration_length { // g_warning ("\\partial not currently supported"); DenemoObject *mud = newchord( $2.t1.a, $2.t1.b,0); mud->type = PARTIAL; /* FIXME - we need to store all four ints then use them to determine how much measure to skip */ mud->user_string = g_strconcat($1.user_string, $2.user_string,NULL); /* FIXME memory leaks on strings concatenated */ $$ = g_list_append(NULL,mud); } | CLEF_ STRING_ { DenemoObject *mud = dnm_newclefobj (cleftypefromname($2.gstr->str)); mud->user_string = g_strconcat($1.user_string, $2.user_string,NULL); /* FIXME memory leaks on strings concatenated */ $$ = g_list_append(NULL,mud); } | TIME_T fraction { DenemoObject *mud = dnm_newtimesigobj ($2.t.a, $2.t.b); mud->user_string = g_strconcat($1.user_string, $2.user_string,NULL); /* FIXME memory leaks on strings concatenated */ $$ = g_list_append(NULL,mud); } | BREAK { /* ignore */ $$ = NULL; } ; command_req: shorthand_command_req { $$ = $1; } | verbose_command_req { $$ = $1; } ; shorthand_command_req: extender_req { $$ = $1; } | hyphen_req { $$ = $1; } | '[' { MALLOC_NODE(n, $1) $$ = g_list_append(NULL, n);/* FIXME denemo should know about this */ } | ']' { MALLOC_NODE(n, $1) $$ = g_list_append(NULL, n);/* FIXME denemo should know about this */ } | BREATHE { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = new Breathing_sign_req; #endif } | E_TILDE { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = new Porrectus_req; #endif } ; verbose_command_req: COMMANDSPANREQUEST bare_int STRING_ { /*TODO: junkme */ LATER_MESSAGE(@$.first_line); #ifdef LATER Span_req * sp = new Span_req; sp-> set_span_dir ( Direction ($2)); sp->set_mus_property ("span-type",$3); sp->set_spot (THIS->here_input ()); $$ = sp; #endif } | MARK DEFAULT { LATER_MESSAGE(@$.first_line); #ifdef LATER Mark_req * m = new Mark_req; $$ = m; #endif } | MARK scalar { LATER_MESSAGE(@$.first_line); #ifdef LATER Mark_req *m = new Mark_req; m->set_mus_property ("label", $2); $$ = m; #endif } | SKIP duration_length { /* denemo doesn't want to know? */ MALLOC_NODE(n, $1) n->type=TEXT; n->user_string = g_strconcat($1.user_string, $2.user_string, NULL); $$ = g_list_append(NULL,n); #ifdef LATER Skip_req * skip = new Skip_req; skip->set_mus_property ("duration", $2); $$ = skip; #endif } | tempo_event { LATER_MESSAGE(@$.first_line); // $$ = $1; } | KEY DEFAULT { LATER_MESSAGE(@$.first_line); #ifdef LATER Key_change_req *key= new Key_change_req; $$ = key; #endif } | KEY NOTENAME_PITCH MUSICMODE { gchar *keyname = keytoname($2.t.a, $2.t.b); DenemoObject *mud; /* the convoluted conversion is due to historical mismatch of lily and denemo*/ if (!strcmp($3.gstr->str, "minor")) mud = dnm_newkeyobj(keynametonumber(keyname)-3, TRUE, 0); else mud = dnm_newkeyobj(keynametonumber(keyname), FALSE, 0); mud->user_string = g_strconcat($1.user_string, $2.user_string, $3.user_string, NULL); $$ = g_list_append(NULL,mud); } ; post_events: { $$ = NULL; } | post_events post_event { if($1) { $$ = g_list_concat($1, $2); } else $$ = $2; } ; post_event: direction_less_event { $$ = $1; } | script_dir direction_reqd_event { /* script_dir is an integer saying whether up down or centred denemo doesn't understand this yet */ u_str($2) = g_strconcat ( $1.user_string, u_str($2), NULL); $$ = $2; } | script_dir direction_less_event { /* script_dir is an integer saying whether up down or centred denemo doesn't understand this yet */ u_str($2) = g_strconcat ( $1.user_string, u_str($2), NULL); $$ = $2; } ; direction_reqd_event: gen_text_def { $$ = $1; } | script_abbreviation { $$ = $1; } ; octave_check: /**/ { } | '=' { $$.i = 0; } | '=' sub_quotes { $$ = $2; } | '=' sup_quotes { $$ = $2; } ; sup_quotes: '\'' { $1.i = 1; $$ = $1; } | sup_quotes '\'' { $1.i ++; $1.user_string = g_strconcat($1.user_string,$2.user_string, NULL);/*FIXME memory leak */ $$ = $1; } ; sub_quotes: ',' { $1.i = 1; $$ = $1; } | sub_quotes ',' { $1.i ++ ; $1.user_string = g_strconcat($1.user_string,$2.user_string, NULL);/*FIXME memory leak */ $$ = $1; } ; steno_pitch: NOTENAME_PITCH { char notename = 'a' + $1.t.a; int enshift = $1.t.b; $$.user_string = $1.user_string; $$.n.enshift = enshift; $$.n.mid_c_offset = pitchtomid_c_offset (notename, 0); } | NOTENAME_PITCH sup_quotes { char notename = 'a' + $1.t.a; int enshift = $1.t.b; int sups=$2.i; $$.user_string = g_strconcat($1.user_string, $2.user_string, NULL); $$.n.enshift = enshift; $$.n.mid_c_offset = pitchtomid_c_offset (notename, sups); } | NOTENAME_PITCH sub_quotes { char notename = 'a' + $1.t.a; int enshift = $1.t.b; int subs = -$2.i; $$.user_string = g_strconcat($1.user_string, $2.user_string, NULL); $$.n.enshift = enshift; $$.n.mid_c_offset = pitchtomid_c_offset (notename, subs); } ; /* ugh. duplication */ steno_tonic_pitch: TONICNAME_PITCH { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $1; #endif } | TONICNAME_PITCH sup_quotes { LATER_MESSAGE(@$.first_line); #ifdef LATER Pitch p = *unsmob_pitch ($1); p.octave_ += $2; $$ = p.smobbed_copy (); #endif } | TONICNAME_PITCH sub_quotes { LATER_MESSAGE(@$.first_line); #ifdef LATER Pitch p =* unsmob_pitch ($1); p.octave_ += -$2; $$ = p.smobbed_copy (); #endif } ; pitch: steno_pitch { $$ = $1; } | explicit_pitch { $$ = $1; } ; explicit_pitch: PITCH embedded_scm { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $2; if (!unsmob_pitch ($2)) { THIS->parser_error (_f ("Expecting musical-pitch value", 3)); $$ = Pitch ().smobbed_copy (); } #endif } ; verbose_duration: DURATION embedded_scm { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $2; if (!unsmob_duration ($2)) { THIS->parser_error (_ ("Must have duration object")); $$ = Duration ().smobbed_copy (); } #endif } ; extender_req: EXTENDER { LATER_MESSAGE(@$.first_line); #ifdef LATER if (!THIS->lexer_->lyric_state_b ()) THIS->parser_error (_ ("Have to be in Lyric mode for lyrics")); $$ = new Extender_req; #endif } ; hyphen_req: HYPHEN { LATER_MESSAGE(@$.first_line); #ifdef LATER if (!THIS->lexer_->lyric_state_b ()) THIS->parser_error (_ ("Have to be in Lyric mode for lyrics")); $$ = new Hyphen_req; #endif } ; direction_less_event: direction_less_char { $$ = $1; } | DYNAMICMARK { MALLOC_NODE(n, $1); ((nodegstr*)n)->gstr = $1.gstr; $$ = g_list_append(NULL, n); } | TONEOPTION { MALLOC_NODE(n, $1); ((nodegstr*)n)->gstr = $1.gstr; $$ = g_list_append(NULL, n); } | tremolo_type { LATER_MESSAGE(@$.first_line); } ; direction_less_char: '(' { MALLOC_NODE(n, $1) $$ = g_list_append(NULL, n); } | ')' { MALLOC_NODE(n, $1) $$ = g_list_append(NULL, n); } | '~' { /* tie */ MALLOC_NODE(n, $1) $$ = g_list_append(NULL, n); } | E_SMALLER { MALLOC_NODE(n, $1) $$ = g_list_append(NULL, n); } | E_BIGGER { MALLOC_NODE(n, $1) $$ = g_list_append(NULL, n); } | E_EXCLAMATION { MALLOC_NODE(n, $1) $$ = g_list_append(NULL, n); } | E_OPEN { LATER_MESSAGE(@$.first_line); #ifdef LATER Span_req* s= new Span_req; $$ = s; s->set_mus_property ("span-type", scm_makfrom0str ( "phrasing-slur")); s->set_spot (THIS->here_input()); #endif } ; full_markup: MARKUP { LATER_MESSAGE(@$.first_line); } ; gen_text_def: full_markup { LATER_MESSAGE(@$.first_line); #ifdef LATER Music *t = MY_MAKE_MUSIC ("TextScriptEvent"); t->set_property ("text", $1); t->set_spot (@$); $$ = t; #endif } /* JAN DYNAMICMARK { MALLOC_NODE(n, $1); ((nodegstr*)n)->gstr = $1.gstr; $$ = g_list_append(NULL, n); } */ | string { MALLOC_NODE(n, $1); ((nodegstr*)n)->gstr = $1.gstr; $$ = g_list_append(NULL, n); } | DIGIT { LATER_MESSAGE(@$.first_line); #ifdef LATER String ds = to_string ($1); Text_script_req* t = new Text_script_req; SCM finger = ly_symbol2scm ("finger"); t->set_mus_property ("text", scm_makfrom0str (ds.to_str0 ())); t->set_mus_property ("text-type" , finger); t->set_spot (THIS->here_input ()); $$ = t; #endif } ; script_abbreviation: '^' { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_makfrom0str ("Hat"); #endif } | '+' { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_makfrom0str ("Plus"); #endif } | '-' { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_makfrom0str ("Dash"); #endif } | '|' { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_makfrom0str ("Bar"); #endif } | '>' { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_makfrom0str ("Larger"); #endif } | '.' { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_makfrom0str ("Dot"); #endif } | '_' { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_makfrom0str ("Underscore"); #endif } ; script_dir: '_' { /* $$ = DOWN; */ } | '^' { /* $$ = UP; */ } | '-' { /* $$ = CENTER; */ } ; absolute_pitch: steno_pitch { $$ = $1; } ; duration_length: multiplied_duration { $$ = $1; } | verbose_duration { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $1; #endif } ; optional_notemode_duration: { $$ = default_duration_; } | multiplied_duration { $$ = $1; default_duration_.t1.a = $1.t1.a; default_duration_.t1.b = $1.t1.b; } | verbose_duration { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $1; THIS->default_duration_ = *unsmob_duration ($$); #endif } ; steno_duration: bare_unsigned dots { int l = 0; if (!is_duration_b ($1.i)) lyerror ("value not a duration");/* $1.i */ else l = intlog2 ($1.i); if($2.i) $$.user_string = g_strconcat($1.user_string, $2.user_string, NULL); $$.t1.a = l; $$.t1.b =$2.i; } | DURATION_IDENTIFIER dots { LATER_MESSAGE(@$.first_line); #ifdef LATER Duration *d =unsmob_duration ($1); Duration k (d->duration_log (),d->dot_count () + $2); $$ = k.smobbed_copy (); #endif } ; multiplied_duration: steno_duration { /* note 4 integers are used for these */ $1.t2.a = 1; $1.t2.b = 1; $$ = $1; } | multiplied_duration '*' bare_unsigned {/* note 4 integers are used for these */ stradd($1,$2); stradd($1,$3); $1.t2.a *= $3.i; $$ = $1; #ifdef LATER $$ = unsmob_duration ($$)->compressed ( $3) .smobbed_copy (); #endif } | multiplied_duration '*' FRACTION {/* note 4 integers are used for these */ stradd($1,$2); stradd($1,$3); $1.t2.a *= $3.t.a; /* numerator of fraction */ $1.t2.b = $3.t.b; /* denominator of fraction */ $$ = $1; #ifdef LATER Rational m (gh_scm2int (ly_car ($3)), gh_scm2int (ly_cdr ($3))); $$ = unsmob_duration ($$)->compressed (m).smobbed_copy (); #endif } ; fraction: FRACTION { $$ = $1; } | UNSIGNED '/' UNSIGNED { $$.user_string = g_strconcat($1.user_string, $2.user_string, $3.user_string, NULL); $$.t.a = $1.i; $$.t.b = $3.i; } ; dots: /* empty */ { $$.i = 0; } | dots '.' { if($1.i == 0){ $$.i = 1; $$.user_string = $2.user_string; } else { $$.user_string = g_strconcat($1.user_string, $2.user_string, NULL);/* FIXME memory leak $2*/ $$.i = $1.i+1; } } ; tremolo_type: ':' { $$.i = 0; } | ':' bare_unsigned { LATER_MESSAGE(@$.first_line); #ifdef LATER if (!is_duration_b ($2)) THIS->parser_error (_f ("not a duration: %d", $2)); $$ = $2; #endif } ; bass_number: DIGIT | UNSIGNED { $$ = $1;} ; bass_mod: '-' { $$.i = -1; } | '+' { $$.i = 1; } | '!' { $$.i = 0; } ; bass_figure: FIGURE_SPACE { $$ = $1; } | bass_number { $$.user_string = $1.user_string; } | bass_figure bass_mod { $$.user_string = g_strconcat($1.user_string, $2.user_string, NULL); } ; br_bass_figure: '[' bass_figure { $$ = $1; } | bass_figure { $$ = $1; } | br_bass_figure ']' { $$ = $1; } ; figure_list: /**/ { $$.user_string = g_strdup(""); } | figure_list br_bass_figure { $$.user_string = g_strconcat($1.user_string, $2.user_string, NULL); } ; figure_spec: FIGURE_OPEN figure_list FIGURE_CLOSE { $$.user_string = g_strconcat($1.user_string, $2.user_string, $3.user_string, NULL); } ; optional_rest: /* empty */ { $$.i = 0; } | REST { $$.i = 1; } ; ; simple_element: pitch exclamations questions octave_check optional_notemode_duration optional_rest { /* pitch is a node* with union a denemo note, exclamations and questions are nodei, optional_notemode_duration is now a node4i, but I don't know how to calculate with the multiplier fraction in the top two ints, optional rest is boolean for the \rest keyword appearing after a note - it turns it into a rest the duration is on the chord structure, the pitch on the note structure. print *(note*)(((DenemoObject*)(((GList*)(((staff*)si->thescore->data)->measures->data))->data))->u.chordval.notes.data) */ DenemoObject *mud = newchord( $5.t1.a, $5.t1.b, 0); if (!note_state_b ()) lyerror (_ ("Have to be in Note mode for notes")); if ($6.i) /* this is a rest vertically placed at the note no special representation in denemo yet */; else { addtone( mud, $1.n.mid_c_offset, $1.n.enshift, 0);/*FIXME should be using $1.n directly */ #define no ((note*)((((chord *)mud->object)->notes)->data)) if ($3.i % 2) { no->showaccidental = TRUE; ((chord *)mud->object)->hasanacc = TRUE; } if ($2.i % 2 ) { no->showaccidental = TRUE; ((chord *)mud->object)->hasanacc = TRUE; } #undef no } mud->user_string = $1.user_string; if ($2.i) stradd ( (*mud),$2); if ($3.i) stradd ( (*mud),$3); stradd ( (*mud),$5); if ($6.i) stradd ( (*mud),$6); /* FIXME memory leaks on strings concatenated */ $$ = g_list_append (NULL,mud); } | RESTNAME optional_notemode_duration { /* denemo wants a chord with no notes */ DenemoObject *mud = newchord( $2.t1.a, $2.t1.b,0); mud->user_string = g_strconcat($1.user_string, $2.user_string, NULL); $$ = g_list_append(NULL,mud); } | SKIPNAME optional_notemode_duration { /* denemo wants a chord with no notes */ DenemoObject *mud = newchord( $2.t1.a, $2.t1.b,0); mud->type = SKIPNAME; mud->user_string = g_strconcat($1.user_string, $2.user_string, NULL); $$ = g_list_append(NULL,mud); } | MULTI_MEASURE_REST optional_notemode_duration { LATER_MESSAGE(@$.first_line); #ifdef LATER Input i = THIS->pop_spot (); Skip_req * sk = new Skip_req; sk->set_mus_property ("duration", $2); Span_req *sp1 = new Span_req; Span_req *sp2 = new Span_req; sp1-> set_span_dir ( START); sp2-> set_span_dir ( STOP); SCM r = scm_makfrom0str ("rest"); sp1->set_mus_property ("span-type", r); sp2->set_mus_property ("span-type", r); Request_chord * rqc1 = new Request_chord (SCM_EOL); rqc1->set_mus_property ("elements", scm_list_n (sp1, SCM_UNDEFINED)); Request_chord * rqc2 = new Request_chord (SCM_EOL); rqc2->set_mus_property ("elements", scm_list_n (sk, SCM_UNDEFINED)); Request_chord * rqc3 = new Request_chord (SCM_EOL); rqc3->set_mus_property ("elements", scm_list_n (sp2, SCM_UNDEFINED)); SCM ms = scm_list_n (rqc1, rqc2, rqc3, SCM_UNDEFINED); $$ = new Sequential_music (SCM_EOL); $$->set_mus_property ("elements", ms); #endif } | STRING_ optional_notemode_duration { DenemoObject *mud = newlyric($2.t1.a, $2.t1.b, $1.gstr->str); mud->user_string = $1.user_string; mud->type = LYRICS; stradd((*mud),$2); $$ = g_list_append(NULL,mud); } | chord { LATER_MESSAGE(@$.first_line); #ifdef LATER Input i = THIS->pop_spot (); if (!THIS->lexer_->chord_state_b ()) THIS->parser_error (_ ("Have to be in Chord mode for chords")); $$ = $1; #endif } ; simul_open: DOUBLE_ANGLE_OPEN ; simul_close: DOUBLE_ANGLE_CLOSE ; chord: steno_tonic_pitch optional_notemode_duration chord_additions chord_subtractions chord_inversion chord_bass { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = Chord::get_chord ($1, $3, $4, $5, $6, $2); $$->set_spot (THIS->here_input ()); #endif }; chord_additions: { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = SCM_EOL; #endif } | CHORD_COLON chord_notes { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $2; #endif } ; chord_notes: chord_step { $$ = $1; } | chord_notes '.' chord_step { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = gh_append2 ($$, $3); #endif } ; chord_subtractions: { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = SCM_EOL; #endif } | CHORD_CARET chord_notes { $$ = $2; } ; chord_inversion: { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = SCM_EOL; #endif } | '/' steno_tonic_pitch { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $2; #endif } ; chord_bass: { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = SCM_EOL; #endif } | CHORD_BASS steno_tonic_pitch { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $2; #endif } ; chord_step: chord_note { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = gh_cons ($1, SCM_EOL); #endif } | CHORDMODIFIER_PITCH { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = gh_cons (unsmob_pitch ($1)->smobbed_copy (), SCM_EOL); #endif } | CHORDMODIFIER_PITCH chord_note { LATER_MESSAGE(@$.first_line); #ifdef LATER /* Ugh. */ $$ = scm_list_n (unsmob_pitch ($1)->smobbed_copy (), $2, SCM_UNDEFINED); #endif } ; chord_note: bare_unsigned { LATER_MESSAGE(@$.first_line); #ifdef LATER Pitch m; m.notename_ = ($1 - 1) % 7; m.octave_ = $1 > 7 ? 1 : 0; m.alteration_ = 0; $$ = m.smobbed_copy (); #endif } | bare_unsigned '+' { LATER_MESSAGE(@$.first_line); #ifdef LATER Pitch m; m.notename_ = ($1 - 1) % 7; m.octave_ = $1 > 7 ? 1 : 0; m.alteration_ = 1; $$ = m.smobbed_copy (); #endif } | bare_unsigned CHORD_MINUS { LATER_MESSAGE(@$.first_line); #ifdef LATER Pitch m; m.notename_ = ($1 - 1) % 7; m.octave_ = $1 > 7 ? 1 : 0; m.alteration_ = -1; $$ = m.smobbed_copy (); #endif } ; /* UTILITIES */ number_expression: number_expression '+' number_term { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_sum ($1, $3); #endif } | number_expression '-' number_term { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_difference ($1, $3); #endif } | number_term ; number_term: number_factor { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $1; #endif } | number_factor '*' number_factor { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_product ($1, $3); #endif } | number_factor '/' number_factor { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_divide ($1, $3); #endif } ; number_factor: '(' number_expression ')' { $$ = $2; } | '-' number_factor { /* %prec UNARY_MINUS */ LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_difference ($2, SCM_UNDEFINED); #endif } | bare_number ; bare_number: UNSIGNED { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = gh_int2scm ($1); #endif } | REAL { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $1; #endif } | NUMBER_IDENTIFIER { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $1; #endif } | REAL CM_T { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = gh_double2scm (gh_scm2double ($1) CM ); #endif } | REAL PT_T { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = gh_double2scm (gh_scm2double ($1) PT); #endif } | REAL IN_T { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = gh_double2scm (gh_scm2double ($1) INCH); #endif } | REAL MM_T { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = gh_double2scm (gh_scm2double ($1) MM); #endif } | REAL CHAR_T { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = gh_double2scm (gh_scm2double ($1) CHAR); #endif } ; bare_unsigned: UNSIGNED { $$ = $1; } | DIGIT { $$ = $1; } ; bare_int: bare_number { LATER_MESSAGE(@$.first_line); #ifdef LATER if (scm_integer_p ($1) == SCM_BOOL_T) { int k = gh_scm2int ($1); $$ = k; } else { THIS->parser_error (_ ("need integer number arg")); $$ = 0; } #endif } | '-' bare_int { $$.i = -$2.i; } ; string: STRING_ { $$ = $1; } | STRING_IDENTIFIER { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = $1; #endif } | string '+' string { LATER_MESSAGE(@$.first_line); #ifdef LATER $$ = scm_string_append (scm_list_n ($1, $3, SCM_UNDEFINED)); #endif } ; exclamations: /* empty */ { $$.i = 0; } | exclamations '!' { if($1.i == 0){ $$.i = 1; $$.user_string = $2.user_string; } else { $$.user_string = g_strconcat($1.user_string, $2.user_string, NULL);/* FIXME memory leak $2*/ $$.i = $1.i+1; } } ; questions: /* empty */ { $$.i = 0; } | questions '?' { if($1.i == 0){ $$.i = 1; $$.user_string = $2.user_string; } else { $$.user_string = g_strconcat($1.user_string, $2.user_string, NULL);/* FIXME memory leak $2*/ $$.i = $1.i+1; } } ; %% #if GTK_MAJOR_VERSION <= 1 #define gtk_window_present(a) #endif static objnode * use_up_ticks (objnode * h, gint ticks) { DenemoObject *figmud = (DenemoObject *) h->data; while (ticks > 0) { h = h->next; figmud = h ? (DenemoObject *) h->data : NULL; if (!figmud) { g_warning ("Insufficient figures for bass part"); return NULL; } ticks -= figmud->basic_durinticks; } return h; } static gboolean create_figures (GList * b, GList * f) { objnode *h = (objnode *) f->data; DenemoObject *figmud; for (figmud = (DenemoObject *) h->data; figmud; h = h->next, figmud = h ? (DenemoObject *) h->data : NULL) { if (figmud->type == CHORD) return FALSE; /* there are already figures present */ } for (; b && b->data; b = b->next) { objnode *g = (objnode *) b->data; DenemoObject *mud; for (mud = (DenemoObject *) g->data; mud; g = g->next, mud = (g ? (DenemoObject *) g->data : NULL)) { if (mud->type == CHORD) { } if (mud->type == TUPOPEN || mud->type == TUPCLOSE || mud->type == GRACE_START || mud->type == GRACE_END) { DenemoObject *figmud = (DenemoObject *) g_malloc0 (sizeof (DenemoObject)); memcpy (figmud, mud, sizeof (DenemoObject)); f->data = g_list_append ((GList *) f->data, figmud); } } f = (f->next ? f->next : g_list_append (f, NULL)); } return TRUE; } /* return next objnode of CHORD (is_figure will be true for h) type */ static objnode * next_figure (objnode * h) { DenemoObject *figmud; for (figmud = (DenemoObject *) h->data; figmud; h = h->next, figmud = h ? (DenemoObject *) h->data : NULL) { if (figmud->type == CHORD) return h; } g_assert (h == NULL); return NULL; } /* Link each chord in BASS to a figure (CHORD) or sequence of them in FIGURES; create blank figures for each note present in BASS if none is present in FIGURES, abort if incomplete figures present */ static void fill_in_figures (DenemoStaff * bass, DenemoStaff * figures) { GList *b = bass->measures, *f = figures->measures; /* if there are no figures create a set cloning the durations from bass */ if (create_figures (b, f)) return; for (b = bass->measures, f = figures->measures; b && b->data; b = b->next, f = f->next) { objnode *g = (objnode *) b->data; objnode *h = (objnode *) f->data; DenemoObject *mud; for (mud = (DenemoObject *) g->data; mud; g = g->next, mud = (g ? (DenemoObject *) g->data : NULL)) { if (mud->type == CHORD) { if (h) { /* set figure of bass chord to the first CHORD (ie figure) * object in the FIGURES list starting at h. * Then move h on over other CHORDs (ie figures) if needed to * use up the duration of the mud->object. * If the list h has run out, abort since we don't know how * much is missing or why */ h = (objnode *) (((chord *) mud->object)->figure); (((chord *) mud->object)->figure) = next_figure (h); if (h) h = use_up_ticks (h, mud->basic_durinticks - ((DenemoObject *) h->data)-> basic_durinticks); } /* if h */ if (((chord *) mud->object)->figure == NULL) /* not yet fixed up this CHORD in BASS */ { lyerror ("Figures are incomplete for Bass - delete the figures or complete them!"); } h = h ? h->next : NULL; } /* if mud is CHORD */ } /* end of for each DenemoObject in the measure */ } /* for each measure */ } /* create the list of measurewidths for si, add measures to short staffs and run set_initial_staffcontexts() to setup the clef etc in the staff structures Fill in any figured bass staff that is short of figures with blank figures. */ static void fixup_measure_widths_and_contexts (DenemoScore * si) { GList *g = si->thescore; DenemoStaff *curstaffstruct = staffstruct (g); int i, num_measures = 0; /* find num_measures of longest staff */ for (g = si->thescore; g; g = g->next) { curstaffstruct = staffstruct (g); i = g_list_length (curstaffstruct->measures); if (num_measures < i) num_measures = i; } /* add measures to short staffs */ for (g = si->thescore; g; g = g->next) { curstaffstruct = staffstruct (g); i = g_list_length (curstaffstruct->measures); while ((num_measures - i++) > 0) curstaffstruct->measures = g_list_append (curstaffstruct->measures, NULL); } /* if(g_list_length(si->measurewidths)) lyerror("si->measurewidths should be zero at this point");*/ g = si->thescore; curstaffstruct = staffstruct (g); i = g_list_length (curstaffstruct->measures); while (i--) si->measurewidths = g_list_append (si->measurewidths, GINT_TO_POINTER (si->measurewidth)); if (si->has_figures) fill_in_figures (si->has_figures->main_staff, si->has_figures->related_staff); set_initial_staffcontexts (si); find_leftmost_allcontexts (si); } /* these scheme identifiers are difficult to track down in lilypond's source tree: \major and \minor in particular I haven't found. There are a group in lilypond/ly/script-init.ly, and clearly the file being parsed could define additional ones, in general we just need to recognize them and pass on the user_string, except where denemo has been equipped to represent them graphically. In this last case we store a token to be returned as the lyval->type, the only case where this is not the same as the token the lexer returns. */ static void insert_scm (int type, gchar * str) { nodegstr *n = (nodegstr *) g_malloc0 (sizeof (nodegstr)); n->type = type; n->gstr = g_string_new (str); g_hash_table_insert (scm_identifiers, (gpointer) str, (gpointer) n); } static void initialize_scm_identifiers (void) { if (scm_identifiers) return; scm_identifiers = g_hash_table_new (g_str_hash, g_str_equal); insert_scm (MUSICMODE, "major"); insert_scm (MUSICMODE, "minor"); insert_scm (TONEOPTION, "thumb"); insert_scm (TONEOPTION, "accent"); insert_scm (TONEOPTION, "marcato"); insert_scm (TONEOPTION, "staccatissimo"); insert_scm (TONEOPTION, "portato"); insert_scm (TONEOPTION, "fermata"); insert_scm (TONEOPTION, "stopped"); insert_scm (TONEOPTION, "staccato"); insert_scm (TONEOPTION, "tenuto"); insert_scm (TONEOPTION, "upbow"); insert_scm (TONEOPTION, "downbow"); insert_scm (TONEOPTION, "lheel"); insert_scm (TONEOPTION, "rheel"); insert_scm (TONEOPTION, "ltoe"); insert_scm (TONEOPTION, "rtoe"); insert_scm (TONEOPTION, "turn"); insert_scm (TONEOPTION, "open"); insert_scm (TONEOPTION, "flageolet"); insert_scm (TONEOPTION, "reverseturn"); insert_scm (TONEOPTION, "trill"); insert_scm (TONEOPTION, "prall"); insert_scm (TONEOPTION, "mordent"); insert_scm (TONEOPTION, "upmordent"); insert_scm (TONEOPTION, "downmordent"); insert_scm (TONEOPTION, "prallprall"); insert_scm (TONEOPTION, "prallup"); insert_scm (TONEOPTION, "pralldown"); insert_scm (TONEOPTION, "lineprall"); insert_scm (TONEOPTION, "prallmordent"); insert_scm (TONEOPTION, "upprall"); insert_scm (TONEOPTION, "downprall"); insert_scm (TONEOPTION, "segno"); insert_scm (TONEOPTION, "coda"); insert_scm (DYNAMICMARK, "ppp"); insert_scm (DYNAMICMARK, "pp"); insert_scm (DYNAMICMARK, "p"); insert_scm (DYNAMICMARK, "mp"); insert_scm (DYNAMICMARK, "mf"); insert_scm (DYNAMICMARK, "f"); insert_scm (DYNAMICMARK, "ff"); insert_scm (DYNAMICMARK, "fff"); insert_scm (DYNAMICMARK, "fff"); insert_scm (DYNAMICMARK, "fp"); insert_scm (DYNAMICMARK, "sf"); insert_scm (DYNAMICMARK, "sff"); insert_scm (DYNAMICMARK, "sp"); insert_scm (DYNAMICMARK, "spp"); insert_scm (DYNAMICMARK, "sfz"); insert_scm (DYNAMICMARK, "rfz"); insert_scm (DYNAMICMARK, "cr"); insert_scm (DYNAMICMARK, "rc"); insert_scm (DYNAMICMARK, "decr"); insert_scm (DYNAMICMARK, "rced"); } /* set parser_error_linenum set parser_error_message, linenum . if EDITOR environment variable not set show a dialog giving TEXT and and offering to exit application or return (for editing the whole file in gui). */ void parser_error (gchar * text, int line_number) { GtkWidget *label; GtkWidget *editbutton; GtkWidget *exitbutton; if( (parser_error_message == NULL) ) { parser_error_message = strdup(text); parser_error_linenum = line_number; } if (!getenv ("EDITOR")) { if (!parser_error_dialog) { /*warningdialog("Unable to load this file - quitting");*/ return(-1); } } else { g_print ("\nAssociated message: %s at line %d\n", text, line_number); } } /* called by lexer at EOF */ void set_trailing_white_space (gchar *trailing) { trailing_white_space = g_strdup (trailing); } static void attach_trailing_white_space (GList *top) { GList *g = g_list_last (top); u_str(g) = g_strconcat(u_str(g), trailing_white_space,NULL); g_free(trailing_white_space); trailing_white_space = NULL; } char * header_str(char *key) { nodeglist *x; char *pt = NULL; int n; x = (nodeglist *) g_hash_table_lookup (name_value_pairs, key); if (x) { pt = u_str(x->branch); if (*pt == '"') pt++; n = strlen(pt) - 1; if (*(pt+n) == '"') *(pt+n) = 0; } return(pt); } static void score_prop_from_lily (DenemoGUI *gui) { DenemoScore *si = gui->si; char *pt; GList *scm; if ((pt = header_str("midi_tempo"))) { si->tempo = atoi(pt); } if ((pt = header_str("lilyversion"))) { gui->lilycontrol.lilyversion = g_string_new(pt); } if (findtok (lily_file, HEADER)) { if ((pt = header_str ("title"))) g_string_assign (si->headerinfo.title, pt); if ((pt = header_str ("subtitle"))) g_string_assign (si->headerinfo.subtitle, pt); if ((pt = header_str ("poet"))) g_string_assign (si->headerinfo.poet, pt); if ((pt = header_str ("composer"))) g_string_assign (si->headerinfo.composer, pt); if ((pt = header_str ("meter"))) g_string_assign (si->headerinfo.meter, pt); if ((pt = header_str ("opus"))) g_string_assign (si->headerinfo.opus, pt); if ((pt = header_str ("arranger"))) g_string_assign (si->headerinfo.arranger, pt); if ((pt = header_str ("instrument"))) g_string_assign (si->headerinfo.instrument, pt); if ((pt = header_str ("dedication"))) g_string_assign (si->headerinfo.dedication, pt); if ((pt = header_str ("piece"))) g_string_assign (si->headerinfo.piece, pt); if ((pt = header_str ("head"))) g_string_assign (si->headerinfo.head, pt); if ((pt = header_str ("copyright"))) g_string_assign (si->headerinfo.copyright, pt); if ((pt = header_str ("footer"))) g_string_assign (si->headerinfo.footer, pt); if ((pt = header_str ("tagline"))) g_string_assign (si->headerinfo.tagline, pt); } for(scm = findtok (lily_file, SCM_T); scm ; scm = scm->next) { if ((pt = strstr (u_str (scm), "set-global-staff-size"))) { int font; if (sscanf (pt+21, " %d", &font) == 1) { gui->lilycontrol.fontsize = font; } else g_warning("%s no font", pt); } if ((pt = strstr (u_str (scm), "set-default-paper-size"))) { char *tmp; char *pt2 = strchr(pt, '\"'); if (pt2) { tmp = g_strdup(pt2+1); pt2 = strchr(tmp, '\"'); if (pt2) { *pt2 = 0; // g_print ("Paper size %s\n", tmp); g_string_assign (gui->lilycontrol.papersize, tmp); *tmp = 0; g_free (tmp); } } if (!pt2) g_warning("%s paper size error", pt); } } } /* from denemo's easylyparser.y note that this function generates a list of DenemoScore structures (one for each \score{} block in the lilypond file, returning the current one (as set in si->theFile->current_scoreblock). This rather clumsy arrangement is historical from when si was the root data structure: see denemo.h */ int lyinput (gchar * filename, DenemoGUI *gui) { FILE *lyin; GList *score_block_list = NULL; initialize_scm_identifiers (); name_value_pairs = g_hash_table_new (g_str_hash, g_str_equal);/* FIXME memory leak */ default_duration_.t1.a = 2; default_duration_.t1.b = 0; init_crescendo_state(); //deletescore(NULL, gui); DenemoScore *si = gui->si; si->thescore = NULL; while (1) { /* keep trying to open the file */ if ((lyin = fopen (filename, "r")) == NULL) { fprintf (stderr, "Cannot open the file: %s\n", filename); return -1; } else { /* file is opened */ /* any old lily parse tree (ie si->lily_file) is already demolished */ lily_file = NULL; parser_error_dialog = NULL; parser_error_message = NULL; /* free_score (si); CHANGE THIS TO FREE ALL THE si in si->thefile->currentDenemoScore list... */ /* in case we are re-entering via reload after error */ lyrestart (lyin); lylineno = 1; /* not done by lexer for some reason */ push_note_state (); while (!feof (lyin)) { lyparse (); if (parser_error_message) { warningdialog("Unable to cope with this file"); return -1; } } if (parser_error_message == NULL) { GList *score = findtok (lily_file, SCORE); if (score) if (create_score_from_lily (si, br (score)) == 0) { GList *top; nodemin *n = (nodemin *) g_malloc0 (sizeof (nodemin)); score_prop_from_lily(gui); //this would be for mutiple score blocks - but they are not then put anywhere... while (score && score->next) { score = findtok (score->next, SCORE); if (score) { DenemoScore *nextsi = (DenemoScore *) g_malloc0 (sizeof (DenemoScore)); init_score (nextsi, gui); create_score_from_lily (nextsi, br (score)); score_block_list = g_list_append (score_block_list, nextsi); } } n->type = TEXT; /* must be g_free-able pointer */ n->user_string = g_strdup (""); top = g_list_append (NULL, n); /* simplify the tree into TEXT and DENEMO_MEASURES nodes */ attach_trailing_white_space (top); si->lily_file = top; fixup_measure_widths_and_contexts (si); return 0; } } /* if successful lily parse */ else { fprintf(stderr, "Parse Error Line %d: %s\n", parser_error_linenum, parser_error_message); return(1); } } reset_initial_lexer_state (); g_assert (lily_file); #ifdef LILYEDIT if (!getenv ("EDITOR")) { long len; gchar *filecontents; fseek (lyin, 0L, SEEK_END); len = ftell (lyin); filecontents = (gchar *) g_malloc (len + 1); /* +1 for NULL terminator */ rewind (lyin); fread (filecontents, len, 1, lyin); *(filecontents + len) = '\0'; fclose (lyin); u_str (lily_file) = filecontents; lily_file->next = NULL; si->lily_file = lily_file; si->curlilynode = lily_file; if (si->textwindow) lily_text_change (si); else create_text_display (si); gui->filename = g_string_new (filename); gtk_widget_set_sensitive (si->textview, TRUE); gtk_widget_set_sensitive (si->scorearea, FALSE); /* put dialog on top - it would be nice to use gtk_dialog_run() but how do you use it? */ if (parser_error_dialog) gtk_window_present ((GtkWindow *) parser_error_dialog); return -1; } else { /* use external editor */ GString *cmd; int ret; fclose (lyin); cmd = g_string_new (getenv ("EDITOR")); g_string_append_printf (cmd, " +%d %s", parser_error_linenum, filename); g_warning ("Using environment variable $EDITOR calling system with %s\n", cmd->str); ret = system (cmd->str); #if 0 if (WIFIGNALED (ret) && (WTERMSIG (ret) == SIGINT || WTERMSIG (ret) == SIGQUIT)) break; #endif if (ret) break; } #endif //LILYEDIT lyerror ("File load failed\n"); return -1; } /* forever */ lyerror ("File load failed\n"); return -1; /* there is no handler for this yet - never has been! */ } #ifdef YYPRINT static gchar * type_name(gint type) { gint i; for(i=0; yytoknum[i] != type; i++) { if (i > YYNTOKENS) return(""); } return yytname[i]; } #endif