denemo-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Denemo-devel] status report


From: Richard Shann
Subject: Re: [Denemo-devel] status report
Date: Tue, 22 Jul 2008 20:47:49 +0100

Thanks for the files - I would like to check them in, if it is all right
with you. 
I have a couple of additions: protection against a crash when the parse
does not work, and parsing LilyPond directives. And, of course,
restoration of the .ly load option. 
I think this is plenty for the release, so if I don't hear back, I'll
get this checked in and we can go.
Thanks very much for this great piece of work.
Richard



On Tue, 2008-07-22 at 23:02 +1000, Roy Rankin wrote:
> Richard,
> 
> Here are my files and a quick summary of the changes
> exportlilypond.c
> 1> always write /context to help parsing and supply voice name
> 2> voice name - name-movement rather than movement-name to aid parsing 
> of name
> 3> midi instruments again output
> 
> lyparser.y
> 1> do not generate error for case score_body lilypond_header
> 2> be more specific for some parsing error
> 3> clear some pointers for score - note your suggestions caused troubles 
> for me
> 
> lyparserfuncs.c
> 1> rewrite break_into_measure to handle recursive identifier
> 2> generate_chords_and_sequentials handles identifiers
> 3> name of first voice is set (old bug)
> 4> added some debugging
> 
> This code is working for my simple tests of both old and new versions of 
> Denemo. I think this gives about the same level of functionality as the 
> lilypond read on the old version, but many valid  syntaxes that can be 
> handled by Denemo fail.
> 
> regards,
> Roy Rankin
> 
> Richard Shann wrote:
> > On Tue, 2008-07-22 at 09:01 +1000, Roy Rankin wrote:
> >> I am currently dumping and reading back simple LilyPond files from 
> >> Denemo.  However, I still have a few issues to cleanup, but if I do not 
> >> manage to get this done tonight, my next chunk of free time will be 
> >> early next week.
> > I have also been getting a chance to look over this, and I think I
> > understand the code as at present.
> > Could you just email me the lyparser.* lyparserfuncs.* files that you
> > have, so that I can understand where you have got to? (Don't email them
> > to the list, as it blocks (large?) attachemts, send them direct or post
> > them up somewhere).
> > I would like to read over what you have done, to see how it fits in to
> > my understanding of the code. It doesn't need to be compilable or
> > anything, just readable.
> > 
> >  As the code no longer needs to keep the input LilyPond as strings for
> > output (which was the purpose of the old code) I think it can be
> > simplified and made more able to cope with LilyPond from a variety of
> > sources. 
> > 
> > In the slightly longer term, I hope be able to select some LilyPond text
> > in a foreign text file (viz. a block of music) and paste it directly
> > into Denemo, using the lyparser (essentially, by surrounding it with
> > \score{ .... } and then parsing it in to a clipboard score).
> > 
> > Best regards,
> > 
> > Richard
> > 
> >> Of course at this point the code is most likely not bullet proof.
> >>
> >> Regards,
> >> Roy Rankin
> >>
> >>
> >> Richard Shann wrote:
> >>> On Sun, 2008-07-20 at 22:15 -0500, Jeremiah Benham wrote:
> >>>> What is left on the TODO list for the release? 
> >>> Well, no one has actually said that they think the release should
> >>> contain a fix for LilyPond import, but Roy is keen that it should be
> >>> possible to load back simple Denemo files saved in LilyPond format, and
> >>> I am keen that it should load some LilyPond files (for which fixes are
> >>> available). I have been getting to grips with the LilyPond load for this
> >>> purpose, but I can't say quite how long it may take.
> >>> It is one of the curses of projects like this that no one says they need
> >>> something until we announce a release, and then it drags on and on. I
> >>> think we should set deadlines for feature requests, announce a schedule
> >>> and, barring showstopping bugs, stick to it.
> >>>
> >>>> I do not want to make any
> >>>> changes to importMidi until the next release. I think I will check out
> >>>> the docs and see what I update. When we make a release it may be
> >>>> embarrassing if the docs are behind. I will look over them and have them
> >>>> update sometime tomorrow.  
> >>> That sounds good, the Print Excerpt has no documentation, I think. There
> >>> is an email from you which I didn't respond to (sorry) about this: the
> >>> situation is that if you have a selection, you probably want that as the
> >>> excerpt, or you may want the whole piece of music as a .png (which is
> >>> only properly supported if it fits on one page, else the user has to dig
> >>> the rest out from .denemo/denemoprint*<n>*.png for n pages), (or even to
> >>> select measures by start measure number/end measure number). The
> >>> interface is supposed to support all this, (but is a bit cheap and
> >>> cheerful?).
> >>>
> >>> Richard
> >>>
> >>>
> >>>
> >>>
> >>>
> >>> _______________________________________________
> >>> Denemo-devel mailing list
> >>> address@hidden
> >>> http://lists.gnu.org/mailman/listinfo/denemo-devel
> >>>
> >>
> >> _______________________________________________
> >> Denemo-devel mailing list
> >> address@hidden
> >> http://lists.gnu.org/mailman/listinfo/denemo-devel
> > 
> > 
> > 
> > _______________________________________________
> > Denemo-devel mailing list
> > address@hidden
> > http://lists.gnu.org/mailman/listinfo/denemo-devel
> > 
> plain text document attachment (lyparser.y)
> %{ // -*-Fundamental-*-
> 
> /*
>       adapted from
>   parser.yy -- Bison/C++ parser for lilypond
> 
>   source file of the GNU LilyPond music typesetter
> 
>   (c)  1997--2001 Han-Wen Nienhuys <address@hidden>
>            Jan Nieuwenhuizen <address@hidden>
>       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 <string.h> /*for memcpy */
> #include <stdlib.h> /* for system() */
> #include <denemo/denemo.h>
> #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 <ctype.h>
> 
> #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<<n)<t) n++;
> return n;
> }
> 
> gboolean
> is_duration_b (int t)
> {
>   return t && t == 1 << intlog2 (t);
> }
> 
> node4i default_duration_;
> 
> static gchar * keytoname(gint pitch, gint enshift) {
> gchar *ret;
>       ret = g_strdup("a");
>       *ret += pitch;
>       for(;enshift>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 <malloc.h>
> #include <stdlib.h>
> #include <stdio.h>
> 
> #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 <generic> TEXT
> %token <gstr> staffcontext voicecontext lyricscontext figuredbasscontext
> %token endcontext
> 
> 
> %token<gstr> MUSICMODE
> %token<gstr> TONEOPTION
> 
> 
> %token<gstr> DYNAMICMARK
> 
> 
> 
> 
> 
> 
> /* tokens which are not keywords */
> %token <generic> AUTOCHANGE
> %token <generic> ALIAS
> %token <generic> APPLY
> %token <generic> ARPEGGIO
> %token <generic> DYNAMICSCRIPT
> %token <generic> ACCEPTS
> %token <generic> ALTERNATIVE
> %token <generic> BAR
> %token <generic> BREAK
> %token <generic> BREATHE
> %token <generic> CHORDMODIFIERS
> %token <generic> CHORDS
> %token <generic> CHAR_T
> %token <generic> CLEF_
> %token <generic> CM_T
> %token <generic> CONSISTS
> %token <generic> SEQUENTIAL
> %token <generic> SIMULTANEOUS
> %token <generic> GROBDESCRIPTIONS
> %token <generic> CONSISTSEND
> %token <generic> DENIES
> %token <generic> DURATION
> %token <generic> EXTENDER
> %token <generic> FIGURES FIGURE_OPEN FIGURE_CLOSE
> %token <generic> FIGURE_BRACKET_CLOSE FIGURE_BRACKET_OPEN
> %token <generic> GLISSANDO
> %token <generic> GRACE 
> %token <generic> HEADER
> %token <generic> HYPHEN
> %token <generic> IN_T
> %token <generic> INVALID
> %token <generic> KEY
> %token <generic> LYRICS
> %token <generic> MARK
> %token <generic> MARKUP
> %token <generic> MULTI_MEASURE_REST
> %token <generic> MIDI
> %token <generic> MM_T
> %token <generic> PITCH
> %token <generic> DEFAULT
> %token <generic> NAME
> %token <generic> PITCHNAMES
> %token <generic> NOTES
> %token <generic> PAPER
> %token <generic> PARTIAL_
> %token <generic> PENALTY
> %token <generic> PROPERTY
> %token <generic> OVERRIDE SET REVERT 
> %token <generic> PT_T
> %token <generic> RELATIVE
> %token <generic> REMOVE
> %token <generic> REPEAT
> %token <generic> ADDLYRICS
> %token <generic> PARTCOMBINE
> %token <generic> SCORE
> %token <generic> SCRIPT
> %token <generic> SKIP
> %token <generic> SPANREQUEST
> %token <generic> STYLESHEET
> %token <generic> COMMANDSPANREQUEST
> %token <generic> TEMPO
> %token <generic> OUTPUTPROPERTY
> %token <generic> TIME_T
> %token <generic> TIMES
> %token <generic> TRANSLATOR
> %token <generic> TRANSPOSE
> %token <generic> TYPE
> %token <generic> UNSET
> %token <minimal> CONTEXT
> %token <generic> LAYOUT
> %token <generic> LYRICSTO
> %token <generic> LYRICMODE
> %token <generic> NEWCONTEXT
> %token <generic> LILYVERSION
> %token <generic> DRUM_PITCH
> %token <generic> MUSIC_FUNCTION
> %token <i> REST
> 
> %token DOUBLE_ANGLE_CLOSE ">>"
> %token DOUBLE_ANGLE_OPEN "<<"
> 
> 
> /* escaped */
> %token <generic> 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 <generic> FIGURE_SPACE
> 
> 
> %type <i>     exclamations questions dots optional_rest 
> %type <i>     bass_number bass_mod
> %type <generic>       br_bass_figure bass_figure figure_list figure_spec
> 
> %token <generic> '='
> %token <generic> '{'
> %token <generic> '<'
> %token <generic> '}'
> %token <generic> '>'
> %token <generic> '|'
> %token <generic> '/'
> %token <generic> '*'
> %token <generic> '('
> %token <generic> ')'
> %token <generic> '~'
> %token <generic> '['
> %token <generic> ']'
> //%token <generic> ">>"
> //%token <generic> "<<"
> 
> %token <i> '.'
> %token <i> '?'
> %token <i> '!'
> 
> %token <i> '\''
> %token <i> ','
> 
> 
> %token <i>    DIGIT
> %token <t>    NOTENAME_PITCH
> %token <t>    TONICNAME_PITCH
> %token <t>    CHORDMODIFIER_PITCH
> %token <id>   DURATION_IDENTIFIER
> %token <t>      FRACTION
> %token <id>   IDENTIFIER
> 
> 
> %token <id>   SCORE_IDENTIFIER
> %token <id>   MUSIC_OUTPUT_DEF_IDENTIFIER
> 
> %token <id>   NUMBER_IDENTIFIER
> %token <id>   REQUEST_IDENTIFIER
> %token <id>   MUSIC_IDENTIFIER TRANSLATOR_IDENTIFIER
> %token <id>   STRING_IDENTIFIER 
> %token <gstr>      SCM_IDENTIFIER 
> %token <generic>      RESTNAME
> %token <generic>      SKIPNAME
> %token <gstr> STRING_   
> %token <generic>      SCM_T
> %token <i>    UNSIGNED
> %token <r>   REAL
> 
> %type <scm> output_def
> %type <scm>   lilypond_header lilypond_header_body toplevel_expression 
> assignment score_block 
> %type <scm>   direction_less_char  direction_less_event direction_reqd_event
> %type <i>     sub_quotes sup_quotes
> %type <scm>   simple_element  event_chord command_element Simple_music  
> Composite_music 
> %type <scm>   chord_body
> %type <scm>   chord_body_element
> %type <scm>   music_function_chord_body
> %type <scm>   chord_body_elements
> %type <scm>   Repeated_music
> %type <scm>     Alternative_music
> %type <i>     tremolo_type
> %type <i>     bare_int  bare_unsigned
> %type <i>     script_dir
> %type <i>     octave_check
> 
> %type <branch>        identifier_init 
> 
> %type <f> steno_duration 
> %type <f>     optional_notemode_duration multiplied_duration
> %type <f>       verbose_duration
>       
> %type <scm>  post_events
> %type <scm>  note_chord_element
> %type <scm> gen_text_def
> %type <scm> full_markup
> %type <n>   steno_pitch pitch absolute_pitch
> %type <n>   explicit_pitch steno_tonic_pitch
> 
> %type <scm>   chord_additions chord_subtractions chord_notes chord_step
> %type <music> chord
> %type <scm>   chord_note chord_inversion chord_bass
> %type <f>     duration_length 
> %type <t>       fraction
> 
> %type <scm>  embedded_scm scalar
> %type <scm>   Music Sequential_music Simultaneous_music 
> %type <scm>   relative_music re_rhythmed_music part_combined_music
> %type <scm>   property_def translator_change
> %type <scm> Music_list
> %type <scm>  music_output_def_body
> %type <scm> shorthand_command_req
> %type <scm>   post_event
> %type <scm> command_req verbose_command_req
> %type <scm>   extender_req
> %type <scm> hyphen_req
> %type <gstr>  string 
> %type <scm>   bare_number number_expression number_term number_factor 
> 
> %type <scm>   score_body
> 
> %type <scm>   translator_spec_block translator_spec_body
> %type <scm>   tempo_event tempo_optional
> %type <scm> notenames_body notenames_block chordmodifiers_block
> %type <scm>   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)  {
>                       GList *ret;
>                       ret = g_list_concat (lily_file, $2);
>               } else {
>               lily_file = $2;
>               }
>       }
>       | lilypond assignment { 
>               if(lily_file)  {
>                       GList *ret;
>                       ret = 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
>                       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 score header");
>               /*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-paper");
>       }
>       | LAYOUT '{' {
>               /* caught by lexer - does not occur*/
>               lyerror ("parser should have caught this - layout");
>       }
>       | 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_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();
>   DenemoScore *si = gui->si;
> 
>   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... */
> 
> 
>         // Calling init_score here would cause piece in header to set to 
> "Movement 2"
>         si->measurewidths = NULL;
>         si->thescore = NULL;
>         
> 
>         /* 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) { 
>       fprintf(stderr,"%s\n",  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);
> 
>                   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 */
> #ifdef LILYEDIT
>                   lily_write_out (top, lily_file, TO_NODE);   
> #endif
>                   attach_trailing_white_space (top);
>                   si->lily_file = top;
>                   si->lily_file = NULL; // stop lilypond file edit 
> restrictions- RRR
>                   fixup_measure_widths_and_contexts (si);
> #ifdef LILYEDIT
>                   /* write out the text to editable display */
>                   create_text_display (gui);  
> #if GTK_MAJOR_VERSION > 1
> /* so that the following toggle starts the scorearea display */
>                   gtk_widget_hide (si->scorearea);    
>                   toggle_top_node (NULL, gui);
> /* present denemo's graphical window first */
>                   gtk_window_present ((GtkWindow *) gui->window);     
> #endif
> 
>                   if (g_list_length (score_block_list) > 0)
>                     {
>                       GList *g;
>                       DenemoScore *nextsi;
>                       for (g = score_block_list; g; g = g->next)
>                         {
>                           nextsi = (DenemoScore *) g->data;
>                           fixup_measure_widths_and_contexts (nextsi);
>                           nextsi->window = si->window;
>                           nextsi->scorearea = si->scorearea;
>                           nextsi->pixmap = si->pixmap;
>                           nextsi->vadjustment = si->vadjustment;
>                           nextsi->vscrollbar = si->vscrollbar;
>                           nextsi->hadjustment = si->hadjustment;
>                           nextsi->hscrollbar = si->hscrollbar;
>                           nextsi->menubar = si->menubar;
>                           nextsi->textbuffer = si->textbuffer;
>                           nextsi->textwindow = si->textwindow;
>                           nextsi->textview = si->textview;
>                           nextsi->musicdatabutton = si->musicdatabutton;
>                           nextsi->sigid = si->sigid;
>                           nextsi->curlilynode = si->curlilynode;
>                           nextsi->lily_file = si->lily_file;
>                           nextsi->prefs = si->prefs;
> /* certain fields are not really score specific - they are file specific - 
> share these */
> 
>                          
> /* but we have no way of sharing has_changed yet FIXmME */
> 
>                         }
> 
>                       /* append a copy of the score block si (the one that 
> the display is hardwired to)
>                          to the list of score_blocks, so that the display can 
> be cycled around by copying
>                          from score_block_list to si  */
>                       nextsi = (DenemoScore *) g_malloc0 (sizeof 
> (DenemoScore));
>                       memcpy (nextsi, si, sizeof (DenemoScore));
>                       score_block_list =
>                         g_list_append (score_block_list, nextsi);
>                       si->scoreblocks = score_block_list;
>                     }
> 
> #endif // LILYEDIT
> 
> 
>                   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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]