]> git.donarmstrong.com Git - lilypond.git/blob - lily/lexer.ll
mention forcing.
[lilypond.git] / lily / lexer.ll
1 %{ // -*-Fundamental-*-
2 /*
3   lexer.ll -- implement the Flex lexer
4
5   source file of the LilyPond music typesetter
6
7   (c) 1996--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8            Jan Nieuwenhuizen <janneke@gnu.org>
9 */
10
11
12 /*
13   backup rules
14
15   after making a change to the lexer rules, run 
16       flex -b <this lexer file>
17   and make sure that 
18       lex.backup
19   contains no backup states, but only the reminder
20       Compressed tables always back up.
21  (don-t forget to rm lex.yy.cc :-)
22  */
23
24
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <errno.h>
28
29 /* Flex >= 2.5.29 fix; FlexLexer.h's multiple include bracing breaks
30    when building the actual lexer.  */
31
32 #define LEXER_CC
33
34 #include <iostream>
35
36 using namespace std;
37
38 #include "music-function.hh"
39 #include "source-file.hh"
40 #include "parse-scm.hh"
41 #include "lily-guile.hh"
42 #include "string.hh"
43 #include "string-convert.hh"
44 #include "lily-lexer.hh"
45 #include "interval.hh"
46 #include "lily-guile.hh"
47 #include "parser.hh"
48 #include "warn.hh"
49 #include "main.hh"
50 #include "version.hh"
51 #include "lilypond-input-version.hh"
52 #include "context-def.hh"
53 #include "identifier-smob.hh"
54
55 /*
56 RH 7 fix (?)
57 */
58 #define isatty HORRIBLEKLUDGE
59
60 void strip_trailing_white (String&);
61 void strip_leading_white (String&);
62 String lyric_fudge (String s);
63 int music_function_type (SCM);
64 SCM lookup_markup_command (String s);
65 bool is_valid_version (String s);
66
67
68 #define start_quote()   \
69         yy_push_state (quote);\
70         yylval.string = new String
71
72 #define start_lyric_quote()     \
73         yy_push_state (lyric_quote);\
74         yylval.string = new String
75
76 #define yylval \
77         (*(YYSTYPE*)lexval)
78
79 #define YY_USER_ACTION  add_lexed_char (YYLeng ());
80 /*
81
82 LYRICS          ({AA}|{TEX})[^0-9 \t\n\f]*
83
84 */
85
86
87 SCM scan_fraction (String);
88 SCM (* scm_parse_error_handler) (void *);
89
90
91
92 %}
93
94 %option c++
95 %option noyywrap
96 %option nodefault
97 %option debug
98 %option yyclass="Lily_lexer"
99 %option stack
100 %option never-interactive 
101 %option warn
102
103 %x chords
104 %x encoding
105 %x figures
106 %x incl
107 %x lyrics
108 %x lyric_quote
109 %x longcomment
110 %x markup 
111 %x notes
112 %x quote
113 %x renameinput
114 %x version
115
116 A               [a-zA-Z]
117 AA              {A}|_
118 N               [0-9]
119 AN              {AA}|{N}
120 PUNCT           [?!:'`]
121 ACCENT          \\[`'"^]
122 NATIONAL        [\001-\006\021-\027\031\036\200-\377]
123 TEX             {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}
124 WORD            {A}{AN}*
125 ALPHAWORD       {A}+
126 DIGIT           {N}
127 UNSIGNED        {N}+
128 E_UNSIGNED      \\{N}+
129 FRACTION        {N}+\/{N}+
130 INT             -?{UNSIGNED}
131 REAL            ({INT}\.{N}*)|(-?\.{N}+)
132 KEYWORD         \\{WORD}
133 WHITE           [ \n\t\f\r]
134 HORIZONTALWHITE         [ \t]
135 BLACK           [^ \n\t\f\r]
136 RESTNAME        [rs]
137 NOTECOMMAND     \\{A}+
138 MARKUPCOMMAND   \\({A}|[-_])+
139 LYRICS          ({AA}|{TEX})[^0-9 \t\n\r\f]*
140 ESCAPED         [nt\\'"]
141 EXTENDER        __
142 HYPHEN          --
143 %%
144
145
146 <*>\r           {
147         // windows-suck-suck-suck
148 }
149
150 <INITIAL,chords,incl,markup,lyrics,notes,figures>{
151   "%{"  {
152         yy_push_state (longcomment);
153   }
154   %[^{\n\r].*[\n\r]     {
155   }
156   %[^{\n\r]     { // backup rule
157   }
158   %[\n\r]       {
159   }
160   %[^{\n\r].*   {
161   }
162   {WHITE}+      {
163
164   }
165 }
166
167 <INITIAL,notes>\\encoding{WHITE}* {
168         yy_push_state (encoding);
169 }
170 <INITIAL,chords,lyrics,notes,figures>\\version{WHITE}*  {
171         yy_push_state (version);
172 }
173 <INITIAL,chords,lyrics,notes,figures>\\renameinput{WHITE}*      {
174         yy_push_state (renameinput);
175 }
176 <encoding>\"[^"]*\"     {
177         String s (YYText () + 1);
178         s = s.left_string (s.index_last ('\"'));
179         set_encoding (s);
180         yy_pop_state ();
181 }
182 <version>\"[^"]*\"     { /* got the version number */
183         String s (YYText () + 1);
184         s = s.left_string (s.index_last ('\"'));
185
186         yy_pop_state ();
187         if (!is_valid_version (s))
188                 return INVALID;
189 }
190 <renameinput>\"[^"]*\"     {
191         String s (YYText ()+1);
192         s = s.left_string (s.index_last ('\"'));
193
194         yy_pop_state();
195         this->here_input().source_file_->name_ = s;
196         progress_indication ("\n");
197         progress_indication (_f ("input renamed to: `%s'", s.to_str0 ()));
198         progress_indication ("\n");
199         scm_module_define (scm_car (scopes_),
200                      ly_symbol2scm ("input-file-name"),
201                      scm_makfrom0str (s.to_str0()));
202
203 }
204 <encoding>.     {
205         LexerError (_ ("No quoted string found after \\encoding").to_str0 ());
206         yy_pop_state ();
207 }
208 <version>.      {
209         LexerError (_ ("No quoted string found after \\version").to_str0 ());
210         yy_pop_state ();
211 }
212 <renameinput>.  {
213         LexerError (_ ("No quoted string found after \\renameinput").to_str0 ());
214         yy_pop_state ();
215 }
216 <longcomment>{
217         [^\%]*          {
218         }
219         \%*[^}%]*               {
220
221         }
222         "%"+"}"         {
223                 yy_pop_state ();
224         }
225         <<EOF>>         {
226                 LexerError (_ ("EOF found inside a comment").to_str0 ());
227                 main_input_b_ = false;
228                 if (! close_input ()) 
229                   yyterminate (); // can't move this, since it actually rets a YY_NULL
230         }
231 }
232
233
234 <INITIAL,chords,lyrics,notes,figures>\\maininput           {
235         if (!main_input_b_)
236         {
237                 start_main_input ();
238                 main_input_b_ = true;
239         }
240         else
241                 error (_ ("\\maininput not allowed outside init files"));
242 }
243
244 <INITIAL,chords,lyrics,figures,notes>\\include           {
245         yy_push_state (incl);
246 }
247 <incl>\"[^"]*\";?   { /* got the include file name */
248 /* FIXME: semicolon? */
249         String s (YYText ()+1);
250         s = s.left_string (s.index_last ('"'));
251
252         new_input (s, sources_);
253         yy_pop_state ();
254 }
255 <incl>\\{BLACK}*;?{WHITE} { /* got the include identifier */
256 /* FIXME: semicolon? */
257         String s = YYText () + 1;
258         strip_trailing_white (s);
259         if (s.length () && (s[s.length () - 1] == ';'))
260           s = s.left_string (s.length () - 1);
261
262         SCM sid = lookup_identifier (s);
263         if (scm_is_string (sid)) {
264                 new_input (ly_scm2string (sid), sources_);
265                 yy_pop_state ();
266         } else { 
267             String msg (_f ("wrong or undefined identifier: `%s'", s ));
268
269             LexerError (msg.to_str0 ());
270             SCM err = scm_current_error_port ();
271             scm_puts ("This value was found in the table: ", err);
272             scm_display (sid, err);
273           }
274 }
275 <incl>\"[^"]*   { // backup rule
276         error (_ ("Missing end quote"));
277         exit (1);
278 }
279 <chords,notes,figures>{RESTNAME}        {
280         const char *s = YYText ();
281         yylval.scm = scm_makfrom0str (s);
282         return RESTNAME;
283 }
284 <chords,notes,figures>R         {
285         return MULTI_MEASURE_REST;
286 }
287 <INITIAL,markup,chords,lyrics,notes,figures>#   { //embedded scm
288         //char const* s = YYText () + 1;
289         char const* s = here_str0 ();
290         int n = 0;
291         SCM sval = ly_parse_scm (s, &n, here_input (),
292                 safe_global_b && main_input_b_);
293
294         if (sval == SCM_UNDEFINED)
295         {
296                 sval = SCM_UNSPECIFIED;
297                 error_level_ = 1;
298         }
299
300         for (int i=0; i < n; i++)
301         {
302                 yyinput ();
303         }
304         char_count_stack_.top () += n;
305
306         if (unpack_identifier (sval) != SCM_UNDEFINED)
307         {
308                 yylval.scm = unpack_identifier(sval);
309                 return identifier_type (yylval.scm);
310         }
311                 
312         yylval.scm = sval;
313         return SCM_T;
314 }
315 <INITIAL,notes,lyrics>{ 
316         \<\<   {
317                 return DOUBLE_ANGLE_OPEN;
318         }
319         \>\>   {
320                 return DOUBLE_ANGLE_CLOSE;
321         }
322 }
323 <figures>{
324         _       {
325                 return FIGURE_SPACE;
326         }
327         \>              {
328                 return FIGURE_CLOSE;
329         }
330         \<      {
331                 return FIGURE_OPEN;
332         }
333 }
334
335 <notes,figures>{
336         {ALPHAWORD}     {
337                 return scan_bare_word (YYText ());
338         }
339
340         {NOTECOMMAND}   {
341                 return scan_escaped_word (YYText () + 1); 
342         }
343         {FRACTION}      {
344                 yylval.scm =  scan_fraction (YYText ());
345                 return FRACTION;
346         }
347
348         {DIGIT}         {
349                 yylval.i = String_convert::dec2int (String (YYText ()));
350                 return DIGIT;
351         }
352         {UNSIGNED}              {
353                 yylval.i = String_convert::dec2int (String (YYText ()));
354                 return UNSIGNED;
355         }
356         {E_UNSIGNED}    {
357                 yylval.i = String_convert::dec2int (String (YYText () +1));
358                 return E_UNSIGNED;
359         }
360
361         \" {
362                 start_quote ();
363         }
364 }
365
366 \"              {
367         start_quote ();
368 }
369 <quote>{
370         \\{ESCAPED}     {
371                 *yylval.string += to_string (escaped_char (YYText ()[1]));
372         }
373         [^\\"]+ {
374                 *yylval.string += YYText ();
375         }
376         \"      {
377
378                 yy_pop_state ();
379
380                 /* yylval is union. Must remember STRING before setting SCM*/
381                 String *sp = yylval.string;
382                 yylval.scm = scm_makfrom0str (sp->to_str0 ());
383                 delete sp;
384                 return STRING;
385         }
386         .       {
387                 *yylval.string += YYText ();
388         }
389 }
390 <lyric_quote>{
391         \\{ESCAPED}     {
392                 *yylval.string += to_string (escaped_char (YYText ()[1]));
393         }
394         [^\\"]+ {
395                 *yylval.string += YYText ();
396         }
397         \"      {
398
399                 yy_pop_state ();
400
401                 /* yylval is union. Must remember STRING before setting SCM*/
402                 String *sp = yylval.string;
403                 yylval.scm = scm_makfrom0str (sp->to_str0 ());
404                 delete sp;
405                 return LYRICS_STRING;
406         }
407         .       {
408                 *yylval.string += YYText ();
409         }
410 }
411
412 <lyrics>{
413         \" {
414                 start_lyric_quote ();
415         }
416         {FRACTION}      {
417                 yylval.scm =  scan_fraction (YYText ());
418                 return FRACTION;
419         }
420         {UNSIGNED}              {
421                 yylval.i = String_convert::dec2int (String (YYText ()));
422                 return UNSIGNED;
423         }
424         {NOTECOMMAND}   {
425                 return scan_escaped_word (YYText () + 1);
426         }
427         {LYRICS} {
428                 /* ugr. This sux. */
429                 String s (YYText ()); 
430                 if (s == "__")
431                         return yylval.i = EXTENDER;
432                 if (s == "--")
433                         return yylval.i = HYPHEN;
434                 s = lyric_fudge (s);
435
436                 char c = s[s.length () - 1];
437                 if (c == '{' ||  c == '}') // brace open is for not confusing dumb tools.
438                         here_input ().warning (
439                                 _ ("Brace found at end of lyric.  Did you forget a space?"));
440                 yylval.scm = scm_makfrom0str (s.to_str0 ());
441
442
443                 return LYRICS_STRING;
444         }
445         . {
446                 return YYText ()[0];
447         }
448 }
449 <chords>{
450         {ALPHAWORD}     {
451                 return scan_bare_word (YYText ());
452         }
453         {NOTECOMMAND}   {
454                 return scan_escaped_word (YYText () + 1);
455         }
456         {FRACTION}      {
457                 yylval.scm =  scan_fraction (YYText ());
458                 return FRACTION;
459         }
460         {UNSIGNED}              {
461                 yylval.i = String_convert::dec2int (String (YYText ()));
462                 return UNSIGNED;
463         }
464         \" {
465                 start_quote ();
466         }
467         -  {
468                 return CHORD_MINUS;
469         }
470         :  {
471                 return CHORD_COLON;
472         }
473         \/\+ {
474                 return CHORD_BASS;
475         }
476         \/  {
477                 return CHORD_SLASH;
478         }
479         \^  {
480                 return CHORD_CARET;
481         }
482         . {
483                 return YYText ()[0];
484         }
485 }
486
487
488 <markup>{
489         \" {
490                 start_quote ();
491         }
492         \< {
493                 return '<';
494         }
495         \> {
496                 return '>';
497         }
498         \\score {
499                 return SCORE;
500         }
501         {MARKUPCOMMAND} {
502                 String str (YYText () + 1);
503                 SCM s = lookup_markup_command (str);
504
505                 if (scm_is_pair (s) && scm_is_symbol (scm_cdr (s)) ) {
506                         yylval.scm = scm_car(s);
507                         SCM tag = scm_cdr(s);
508                         if (tag == ly_symbol2scm("markup0"))
509                                 return MARKUP_HEAD_MARKUP0;
510                         if (tag == ly_symbol2scm("empty"))
511                                 return MARKUP_HEAD_EMPTY;
512                         else if (tag == ly_symbol2scm ("markup0-markup1"))
513                                 return MARKUP_HEAD_MARKUP0_MARKUP1;
514                         else if (tag == ly_symbol2scm ("markup-list0"))
515                                 return MARKUP_HEAD_LIST0;
516                         else if (tag == ly_symbol2scm ("scheme0"))
517                                 return MARKUP_HEAD_SCM0;
518                         else if (tag == ly_symbol2scm ("scheme0-scheme1"))
519                                 return MARKUP_HEAD_SCM0_SCM1;
520                         else if (tag == ly_symbol2scm ("scheme0-markup1"))
521                                 return MARKUP_HEAD_SCM0_MARKUP1;
522                         else if (tag == ly_symbol2scm ("scheme0-scheme1-markup2"))
523                                 return MARKUP_HEAD_SCM0_SCM1_MARKUP2;
524                         else if (tag == ly_symbol2scm ("scheme0-scheme1-scheme2"))
525                                 return MARKUP_HEAD_SCM0_SCM1_SCM2;
526                         else {
527                                 programming_error ("No parser tag defined for this signature. Abort"); 
528                                 ly_display_scm (s);
529                                 assert(false);
530                         }
531                 } else
532                         return scan_escaped_word (str);
533         }
534         [{}]    {
535                 return YYText ()[0];
536         }
537         [^#{}"\\ \t\n\r\f]+ {
538                 String s (YYText ()); 
539
540                 char c = s[s.length () - 1];
541                 /* brace open is for not confusing dumb tools.  */
542                 if (c == '{' ||  c == '}')
543                         here_input ().warning (
544                                 _ ("Brace found at end of markup.  Did you forget a space?"));
545                 yylval.scm = scm_makfrom0str (s.to_str0 ());
546
547
548                 return STRING;
549         }
550         .  {
551                 return YYText()[0];
552         }
553 }
554
555 <<EOF>> {
556         if (main_input_b_)
557         {
558                 main_input_b_ = false;
559                 if (!close_input ())
560                 /* Returns YY_NULL */
561                         yyterminate ();
562         }
563         else if (!close_input ())
564                 /* Returns YY_NULL */
565                 yyterminate ();
566 }
567
568
569 {WORD}  {
570         return scan_bare_word (YYText ());
571 }
572 {KEYWORD}       {
573         return scan_escaped_word (YYText () + 1);
574 }
575 {REAL}          {
576         Real r;
577         int cnv=sscanf (YYText (), "%lf", &r);
578         assert (cnv == 1);
579
580         yylval.scm = scm_make_real (r);
581         return REAL;
582 }
583
584 {UNSIGNED}      {
585         yylval.i = String_convert::dec2int (String (YYText ()));
586         return UNSIGNED;
587 }
588
589
590 [{}]    {
591
592         return YYText ()[0];
593 }
594 [*:=]           {
595         char c = YYText ()[0];
596
597         return c;
598 }
599
600 <INITIAL,notes,figures>.        {
601         return YYText ()[0];
602 }
603
604 <INITIAL,lyrics,notes,figures>\\. {
605     char c= YYText ()[1];
606
607     switch (c) {
608     case '>':
609         return E_BIGGER;
610     case '<':
611         return E_SMALLER;
612     case '!':
613         return E_EXCLAMATION;
614     case '(':
615         return E_OPEN;
616     case ')':
617         return E_CLOSE;
618     case '[':
619         return E_LEFTSQUARE;
620     case ']':
621         return E_RIGHTSQUARE;
622     case '~':
623         return E_TILDE;
624     case '\\':
625         return E_BACKSLASH;
626
627     default:
628         return E_CHAR;
629     }
630 }
631
632 <*>.            {
633         String msg = _f ("invalid character: `%c'", YYText ()[0]);
634         LexerError (msg.to_str0 ());
635         return YYText ()[0];
636 }
637
638 %%
639
640 void
641 Lily_lexer::push_chord_state (SCM tab)
642 {
643         pitchname_tab_stack_ = scm_cons (tab, pitchname_tab_stack_);
644         yy_push_state (chords);
645 }
646
647 void
648 Lily_lexer::push_figuredbass_state ()
649 {
650         yy_push_state (figures);
651 }
652
653 void
654 Lily_lexer::push_initial_state ()
655 {
656         yy_push_state (INITIAL);
657 }
658
659 void
660 Lily_lexer::push_lyric_state ()
661 {
662         yy_push_state (lyrics);
663 }
664
665 void
666 Lily_lexer::push_markup_state ()
667 {
668         yy_push_state (markup);
669 }
670
671 void
672 Lily_lexer::push_note_state (SCM tab)
673 {
674         pitchname_tab_stack_ = scm_cons (tab, pitchname_tab_stack_);
675         yy_push_state (notes);
676 }
677
678 void
679 Lily_lexer::pop_state ()
680 {
681         if (YYSTATE == notes || YYSTATE == chords)
682                 pitchname_tab_stack_ = scm_cdr (pitchname_tab_stack_);
683         yy_pop_state ();
684 }
685
686 int
687 Lily_lexer::identifier_type (SCM sid)
688 {
689         int k = try_special_identifiers (&yylval.scm , sid);
690         return k >= 0  ? k : SCM_IDENTIFIER;
691 }
692
693
694 int
695 Lily_lexer::scan_escaped_word (String str)
696 {
697         // use more SCM for this.
698
699 //      SCM sym = ly_symbol2scm (str.to_str0 ());
700
701         int l = lookup_keyword (str);
702         if (l != -1) {
703                 return l;
704         }
705         SCM sid = lookup_identifier (str);
706         if (is_music_function (sid))
707         {
708                 yylval.scm = get_music_function_transform (sid);
709                 
710                 return music_function_type (yylval.scm);
711         }
712
713         if (sid != SCM_UNDEFINED)
714         {
715                 yylval.scm = sid;
716                 return identifier_type (sid);
717         }
718
719         String msg (_f ("unknown escaped string: `\\%s'", str));        
720         LexerError (msg.to_str0 ());
721
722         yylval.scm = scm_makfrom0str (str.to_str0 ());
723
724         return STRING;
725 }
726
727 int
728 Lily_lexer::scan_bare_word (String str)
729 {
730         SCM sym = ly_symbol2scm (str.to_str0 ());
731         if ((YYSTATE == notes) || (YYSTATE == chords)) {
732                 SCM handle = SCM_BOOL_F;
733                 if (scm_is_pair (pitchname_tab_stack_))
734                         handle = scm_hashq_get_handle (scm_car (pitchname_tab_stack_), sym);
735                 
736                 if (scm_is_pair (handle)) {
737                         yylval.scm = scm_cdr (handle);
738                         if (unsmob_pitch (yylval.scm)) 
739                             return (YYSTATE == notes) ? NOTENAME_PITCH : TONICNAME_PITCH;
740                         else if (scm_is_symbol (yylval.scm))
741                             return DRUM_PITCH;
742                 }
743                 else if ((handle = scm_hashq_get_handle (chordmodifier_tab_, sym))!= SCM_BOOL_F)
744                 {
745                     yylval.scm = scm_cdr (handle);
746                     return CHORD_MODIFIER;
747                 }
748         }
749
750         yylval.scm = scm_makfrom0str (str.to_str0 ());
751         return STRING;
752 }
753
754 bool
755 Lily_lexer::is_note_state () const
756 {
757         return YY_START == notes;
758 }
759
760 bool
761 Lily_lexer::is_chord_state () const
762 {
763         return YY_START == chords;
764 }
765
766 bool
767 Lily_lexer::is_lyric_state () const
768 {
769         return YY_START == lyrics;
770 }
771
772 bool
773 Lily_lexer::is_figure_state () const
774 {
775         return YY_START == figures;
776 }
777
778 /*
779  urg, belong to String (_convert)
780  and should be generalised 
781  */
782 void
783 strip_leading_white (String&s)
784 {
785         int i=0;
786         for (;  i < s.length (); i++) 
787                 if (!isspace (s[i]))
788                         break;
789
790         s = s.nomid_string (0, i);
791 }
792
793 void
794 strip_trailing_white (String&s)
795 {
796         int i=s.length ();      
797         while (i--) 
798                 if (!isspace (s[i]))
799                         break;
800
801         s = s.left_string (i+1);
802 }
803
804
805
806 /* 2.1.2x something -> \property -> \set. */ 
807 Lilypond_version oldest_version ("2.3.22");
808
809
810 bool
811 is_valid_version (String s)
812 {
813   Lilypond_version current ( MAJOR_VERSION "." MINOR_VERSION "." PATCH_LEVEL );
814   Lilypond_version ver (s);
815   if (! ((ver >= oldest_version) && (ver <= current)))
816         {       
817                 non_fatal_error (_f ("Incorrect lilypond version: %s (%s, %s)", ver.to_string (), oldest_version.to_string (), current.to_string ()));
818                 non_fatal_error (_ ("Consider updating the input with the convert-ly script")); 
819                 return false;
820     }
821   return true;
822 }
823         
824
825 /*
826   substitute _ and \,
827 */
828 String
829 lyric_fudge (String s)
830 {
831   char  * chars  =s.get_copy_str0 ();
832
833   for (char * p = chars; *p ; p++)
834     {
835       if (*p == '_' && (p == chars || *(p-1) != '\\'))
836         *p = ' ';
837     }
838   
839   s = String (chars);
840   delete[] chars;
841
842   int i =0;     
843   if ((i=s.index ("\\,")) != -1)   // change "\," to TeX's "\c "
844     {
845       * (s.get_str0 () + i + 1) = 'c';
846       s = s.left_string (i+2) + " " + s.right_string (s.length ()-i-2);
847     }
848
849   return s;
850 }
851
852 /*
853 Convert "NUM/DEN" into a '(NUM . DEN) cons.
854 */
855 SCM
856 scan_fraction (String frac)
857 {
858         int i = frac.index ('/');
859         int l = frac.length ();
860         String left = frac.left_string (i);
861         String right = frac.right_string (l - i - 1);
862
863         int n = String_convert::dec2int (left);
864         int d = String_convert::dec2int (right);
865         return scm_cons (scm_int2num (n), scm_int2num (d));
866 }
867
868 // Breaks for flex 2.5.31
869 #if 0
870 /* avoid silly flex induced gcc warnings */
871 static void yy_push_state (int) {;}
872 static void yy_pop_state () {;}
873 static int yy_top_state () { return 0; }
874
875 static void
876 avoid_silly_flex_induced_gcc_warnings ()
877 {
878         (void)yy_start_stack_ptr;
879         (void)yy_start_stack_depth;
880         (void)yy_start_stack;
881         yy_push_state (0);
882         yy_pop_state ();
883         yy_top_state ();
884         avoid_silly_flex_induced_gcc_warnings ();
885 }
886 #endif
887
888 SCM
889 lookup_markup_command (String s)
890 {
891         SCM proc = ly_scheme_function ("lookup-markup-command");
892         return scm_call_1 (proc, scm_makfrom0str (s.to_str0 ()));
893 }
894
895
896 int
897 music_function_type (SCM func)
898 {
899         SCM type= scm_object_property (func, ly_symbol2scm ("music-function-signature-keyword"));
900         if (type == ly_symbol2scm ("scm"))
901         {
902                 return MUSIC_FUNCTION_SCM;
903         }
904         else if (type == ly_symbol2scm ("music"))
905         {
906                 return MUSIC_FUNCTION_MUSIC;
907         }
908         else if (type == ly_symbol2scm ("scm-music"))
909         {
910                 return MUSIC_FUNCTION_SCM_MUSIC;
911         }
912         else if (type == ly_symbol2scm ("scm-scm"))
913         {
914                 return MUSIC_FUNCTION_SCM_SCM;
915         }
916         else if (type == ly_symbol2scm ("music-music"))
917         {
918                 return MUSIC_FUNCTION_MUSIC_MUSIC;
919         }
920         else if (type == ly_symbol2scm ("scm-music-music"))
921         {
922                 return MUSIC_FUNCTION_SCM_MUSIC_MUSIC;
923         }
924         else if (type == ly_symbol2scm ("scm-scm-music"))
925         {
926                 return MUSIC_FUNCTION_SCM_SCM_MUSIC;
927         }
928         else if (type == ly_symbol2scm ("markup"))
929         {
930                 return MUSIC_FUNCTION_MARKUP;
931         }
932         else if (type == ly_symbol2scm ("markup-music"))
933         {
934                 return MUSIC_FUNCTION_MARKUP_MUSIC;
935         }
936         else if (type == ly_symbol2scm ("markup-markup"))
937         {
938                 return MUSIC_FUNCTION_MARKUP_MARKUP;
939         }
940         else if (type == ly_symbol2scm ("markup-music-music"))
941         {
942                 return MUSIC_FUNCTION_MARKUP_MUSIC_MUSIC;
943         }
944         else if (type == ly_symbol2scm ("markup-markup-music"))
945         {
946                 return MUSIC_FUNCTION_MARKUP_MARKUP_MUSIC;
947         }
948         else if (type == ly_symbol2scm ("noarg"))
949         {
950                 return MUSIC_FUNCTION;
951         }
952         else
953                 {
954                 /* TODO: print location */
955                 error ("Can not find signature for music function.");
956                 }
957
958         return MUSIC_FUNCTION_SCM;
959 }