]> git.donarmstrong.com Git - lilypond.git/blob - lily/lexer.ll
add < > to markup lexer mode (backportme)
[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,lyrics,figures,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 (_f ("Renaming input to: `%s'", s.to_str0 ()));
197         progress_indication ("\n");
198         scm_module_define (scm_car (scopes_),
199                      ly_symbol2scm ("input-file-name"),
200                      scm_makfrom0str (s.to_str0 ()));
201
202 }
203 <encoding>.     {
204         LexerError (_ ("No quoted string found after \\encoding").to_str0 ());
205         yy_pop_state ();
206 }
207 <version>.      {
208         LexerError (_ ("No quoted string found after \\version").to_str0 ());
209         yy_pop_state ();
210 }
211 <renameinput>.  {
212         LexerError (_ ("No quoted string found after \\renameinput").to_str0 ());
213         yy_pop_state ();
214 }
215 <longcomment>{
216         [^\%]*          {
217         }
218         \%*[^}%]*               {
219
220         }
221         "%"+"}"         {
222                 yy_pop_state ();
223         }
224         <<EOF>>         {
225                 LexerError (_ ("EOF found inside a comment").to_str0 ());
226                 main_input_b_ = false;
227                 if (! close_input ()) 
228                   yyterminate (); // can't move this, since it actually rets a YY_NULL
229         }
230 }
231
232
233 <INITIAL,chords,lyrics,notes,figures>\\maininput           {
234         if (!main_input_b_)
235         {
236                 start_main_input ();
237                 main_input_b_ = true;
238         }
239         else
240                 error (_ ("\\maininput not allowed outside init files"));
241 }
242
243 <INITIAL,chords,lyrics,figures,notes>\\include           {
244         yy_push_state (incl);
245 }
246 <incl>\"[^"]*\"   { /* got the include file name */
247         String s (YYText ()+1);
248         s = s.left_string (s.index_last ('"'));
249
250         new_input (s, sources_);
251         yy_pop_state ();
252 }
253 <incl>\\{BLACK}*{WHITE} { /* got the include identifier */
254         String s = YYText () + 1;
255         strip_trailing_white (s);
256         if (s.length () && (s[s.length () - 1] == ';'))
257           s = s.left_string (s.length () - 1);
258
259         SCM sid = lookup_identifier (s);
260         if (scm_is_string (sid)) {
261                 new_input (ly_scm2string (sid), sources_);
262                 yy_pop_state ();
263         } else { 
264             String msg (_f ("wrong or undefined identifier: `%s'", s ));
265
266             LexerError (msg.to_str0 ());
267             SCM err = scm_current_error_port ();
268             scm_puts ("This value was found in the table: ", err);
269             scm_display (sid, err);
270           }
271 }
272 <incl>\"[^"]*   { // backup rule
273         error (_ ("Missing end quote"));
274         exit (1);
275 }
276 <chords,notes,figures>{RESTNAME}        {
277         const char *s = YYText ();
278         yylval.scm = scm_makfrom0str (s);
279         return RESTNAME;
280 }
281 <chords,notes,figures>R         {
282         return MULTI_MEASURE_REST;
283 }
284 <INITIAL,markup,chords,lyrics,notes,figures>#   { //embedded scm
285         //char const* s = YYText () + 1;
286         char const* s = here_str0 ();
287         int n = 0;
288         SCM sval = ly_parse_scm (s, &n, here_input (),
289                 safe_global_b && main_input_b_);
290
291         if (sval == SCM_UNDEFINED)
292         {
293                 sval = SCM_UNSPECIFIED;
294                 error_level_ = 1;
295         }
296
297         for (int i=0; i < n; i++)
298         {
299                 yyinput ();
300         }
301         char_count_stack_.top () += n;
302
303         if (unpack_identifier (sval) != SCM_UNDEFINED)
304         {
305                 yylval.scm = unpack_identifier(sval);
306                 return identifier_type (yylval.scm);
307         }
308                 
309         yylval.scm = sval;
310         return SCM_T;
311 }
312 <INITIAL,notes,lyrics>{ 
313         \<\<   {
314                 return DOUBLE_ANGLE_OPEN;
315         }
316         \>\>   {
317                 return DOUBLE_ANGLE_CLOSE;
318         }
319 }
320 <figures>{
321         _       {
322                 return FIGURE_SPACE;
323         }
324         \>              {
325                 return FIGURE_CLOSE;
326         }
327         \<      {
328                 return FIGURE_OPEN;
329         }
330 }
331
332 <notes,figures>{
333         {ALPHAWORD}     {
334                 return scan_bare_word (YYText ());
335         }
336
337         {NOTECOMMAND}   {
338                 return scan_escaped_word (YYText () + 1); 
339         }
340         {FRACTION}      {
341                 yylval.scm =  scan_fraction (YYText ());
342                 return FRACTION;
343         }
344
345         {DIGIT}         {
346                 yylval.i = String_convert::dec2int (String (YYText ()));
347                 return DIGIT;
348         }
349         {UNSIGNED}              {
350                 yylval.i = String_convert::dec2int (String (YYText ()));
351                 return UNSIGNED;
352         }
353         {E_UNSIGNED}    {
354                 yylval.i = String_convert::dec2int (String (YYText () +1));
355                 return E_UNSIGNED;
356         }
357         \" {
358                 start_quote ();
359         }
360 }
361
362 \"              {
363         start_quote ();
364 }
365 <quote>{
366         \\{ESCAPED}     {
367                 *yylval.string += to_string (escaped_char (YYText ()[1]));
368         }
369         [^\\"]+ {
370                 *yylval.string += YYText ();
371         }
372         \"      {
373
374                 yy_pop_state ();
375
376                 /* yylval is union. Must remember STRING before setting SCM*/
377                 String *sp = yylval.string;
378                 yylval.scm = scm_makfrom0str (sp->to_str0 ());
379                 delete sp;
380                 return STRING;
381         }
382         .       {
383                 *yylval.string += YYText ();
384         }
385 }
386 <lyric_quote>{
387         \\{ESCAPED}     {
388                 *yylval.string += to_string (escaped_char (YYText ()[1]));
389         }
390         [^\\"]+ {
391                 *yylval.string += YYText ();
392         }
393         \"      {
394
395                 yy_pop_state ();
396
397                 /* yylval is union. Must remember STRING before setting SCM*/
398                 String *sp = yylval.string;
399                 yylval.scm = scm_makfrom0str (sp->to_str0 ());
400                 delete sp;
401                 return LYRICS_STRING;
402         }
403         .       {
404                 *yylval.string += YYText ();
405         }
406 }
407
408 <lyrics>{
409         \" {
410                 start_lyric_quote ();
411         }
412         {FRACTION}      {
413                 yylval.scm =  scan_fraction (YYText ());
414                 return FRACTION;
415         }
416         {UNSIGNED}              {
417                 yylval.i = String_convert::dec2int (String (YYText ()));
418                 return UNSIGNED;
419         }
420         {NOTECOMMAND}   {
421                 return scan_escaped_word (YYText () + 1);
422         }
423         {LYRICS} {
424                 /* ugr. This sux. */
425                 String s (YYText ()); 
426                 if (s == "__")
427                         return yylval.i = EXTENDER;
428                 if (s == "--")
429                         return yylval.i = HYPHEN;
430                 s = lyric_fudge (s);
431
432                 char c = s[s.length () - 1];
433                 if (c == '{' ||  c == '}') // brace open is for not confusing dumb tools.
434                         here_input ().warning (
435                                 _ ("Brace found at end of lyric.  Did you forget a space?"));
436                 yylval.scm = scm_makfrom0str (s.to_str0 ());
437
438
439                 return LYRICS_STRING;
440         }
441         . {
442                 return YYText ()[0];
443         }
444 }
445 <chords>{
446         {ALPHAWORD}     {
447                 return scan_bare_word (YYText ());
448         }
449         {NOTECOMMAND}   {
450                 return scan_escaped_word (YYText () + 1);
451         }
452         {FRACTION}      {
453                 yylval.scm =  scan_fraction (YYText ());
454                 return FRACTION;
455         }
456         {UNSIGNED}              {
457                 yylval.i = String_convert::dec2int (String (YYText ()));
458                 return UNSIGNED;
459         }
460         \" {
461                 start_quote ();
462         }
463         -  {
464                 return CHORD_MINUS;
465         }
466         :  {
467                 return CHORD_COLON;
468         }
469         \/\+ {
470                 return CHORD_BASS;
471         }
472         \/  {
473                 return CHORD_SLASH;
474         }
475         \^  {
476                 return CHORD_CARET;
477         }
478         . {
479                 return YYText ()[0];
480         }
481 }
482
483
484 <markup>{
485         \" {
486                 start_quote ();
487         }
488         \< {
489                 return '<';
490         }
491         \> {
492                 return '>';
493         }
494         \\score {
495                 return SCORE;
496         }
497         {MARKUPCOMMAND} {
498                 String str (YYText () + 1);
499                 SCM s = lookup_markup_command (str);
500
501                 if (scm_is_pair (s) && scm_is_symbol (scm_cdr (s)) ) {
502                         yylval.scm = scm_car(s);
503                         SCM tag = scm_cdr(s);
504                         if (tag == ly_symbol2scm("markup0"))
505                                 return MARKUP_HEAD_MARKUP0;
506                         if (tag == ly_symbol2scm("empty"))
507                                 return MARKUP_HEAD_EMPTY;
508                         else if (tag == ly_symbol2scm ("markup0-markup1"))
509                                 return MARKUP_HEAD_MARKUP0_MARKUP1;
510                         else if (tag == ly_symbol2scm ("markup-list0"))
511                                 return MARKUP_HEAD_LIST0;
512                         else if (tag == ly_symbol2scm ("scheme0"))
513                                 return MARKUP_HEAD_SCM0;
514                         else if (tag == ly_symbol2scm ("scheme0-scheme1"))
515                                 return MARKUP_HEAD_SCM0_SCM1;
516                         else if (tag == ly_symbol2scm ("scheme0-markup1"))
517                                 return MARKUP_HEAD_SCM0_MARKUP1;
518                         else if (tag == ly_symbol2scm ("scheme0-scheme1-markup2"))
519                                 return MARKUP_HEAD_SCM0_SCM1_MARKUP2;
520                         else if (tag == ly_symbol2scm ("scheme0-scheme1-scheme2"))
521                                 return MARKUP_HEAD_SCM0_SCM1_SCM2;
522                         else {
523                                 programming_error ("No parser tag defined for this signature. Abort"); 
524                                 ly_display_scm (s);
525                                 assert(false);
526                         }
527                 } else
528                         return scan_escaped_word (str);
529         }
530         [{}]    {
531                 return YYText ()[0];
532         }
533         [^<>#{}"\\ \t\n\r\f]+ {
534                 String s (YYText ()); 
535
536                 char c = s[s.length () - 1];
537                 /* brace open is for not confusing dumb tools.  */
538                 if (c == '{' ||  c == '}')
539                         here_input ().warning (
540                                 _ ("Brace found at end of markup.  Did you forget a space?"));
541                 yylval.scm = scm_makfrom0str (s.to_str0 ());
542
543
544                 return STRING;
545         }
546         .  {
547                 return YYText()[0];
548         }
549 }
550
551 <<EOF>> {
552         if (main_input_b_)
553         {
554                 main_input_b_ = false;
555                 if (!close_input ())
556                 /* Returns YY_NULL */
557                         yyterminate ();
558         }
559         else if (!close_input ())
560                 /* Returns YY_NULL */
561                 yyterminate ();
562 }
563
564
565 {WORD}  {
566         return scan_bare_word (YYText ());
567 }
568 {KEYWORD}       {
569         return scan_escaped_word (YYText () + 1);
570 }
571 {REAL}          {
572         Real r;
573         int cnv=sscanf (YYText (), "%lf", &r);
574         assert (cnv == 1);
575
576         yylval.scm = scm_make_real (r);
577         return REAL;
578 }
579
580 {UNSIGNED}      {
581         yylval.i = String_convert::dec2int (String (YYText ()));
582         return UNSIGNED;
583 }
584
585
586 [{}]    {
587
588         return YYText ()[0];
589 }
590 [*:=]           {
591         char c = YYText ()[0];
592
593         return c;
594 }
595
596 <INITIAL,notes,figures>.        {
597         return YYText ()[0];
598 }
599
600 <INITIAL,lyrics,notes,figures>\\. {
601     char c= YYText ()[1];
602
603     switch (c) {
604     case '>':
605         return E_BIGGER;
606     case '<':
607         return E_SMALLER;
608     case '!':
609         return E_EXCLAMATION;
610     case '(':
611         return E_OPEN;
612     case ')':
613         return E_CLOSE;
614     case '[':
615         return E_LEFTSQUARE;
616     case ']':
617         return E_RIGHTSQUARE;
618     case '~':
619         return E_TILDE;
620     case '\\':
621         return E_BACKSLASH;
622
623     default:
624         return E_CHAR;
625     }
626 }
627
628 <*>.            {
629         String msg = _f ("invalid character: `%c'", YYText ()[0]);
630         LexerError (msg.to_str0 ());
631         return YYText ()[0];
632 }
633
634 %%
635
636 void
637 Lily_lexer::push_chord_state (SCM tab)
638 {
639         pitchname_tab_stack_ = scm_cons (tab, pitchname_tab_stack_);
640         yy_push_state (chords);
641 }
642
643 void
644 Lily_lexer::push_figuredbass_state ()
645 {
646         yy_push_state (figures);
647 }
648
649 void
650 Lily_lexer::push_initial_state ()
651 {
652         yy_push_state (INITIAL);
653 }
654
655 void
656 Lily_lexer::push_lyric_state ()
657 {
658         yy_push_state (lyrics);
659 }
660
661 void
662 Lily_lexer::push_markup_state ()
663 {
664         yy_push_state (markup);
665 }
666
667 void
668 Lily_lexer::push_note_state (SCM tab)
669 {
670         pitchname_tab_stack_ = scm_cons (tab, pitchname_tab_stack_);
671         yy_push_state (notes);
672 }
673
674 void
675 Lily_lexer::pop_state ()
676 {
677         if (YYSTATE == notes || YYSTATE == chords)
678                 pitchname_tab_stack_ = scm_cdr (pitchname_tab_stack_);
679         yy_pop_state ();
680 }
681
682 int
683 Lily_lexer::identifier_type (SCM sid)
684 {
685         int k = try_special_identifiers (&yylval.scm , sid);
686         return k >= 0  ? k : SCM_IDENTIFIER;
687 }
688
689
690 int
691 Lily_lexer::scan_escaped_word (String str)
692 {
693         // use more SCM for this.
694
695 //      SCM sym = ly_symbol2scm (str.to_str0 ());
696
697         int l = lookup_keyword (str);
698         if (l != -1) {
699                 return l;
700         }
701         SCM sid = lookup_identifier (str);
702         if (is_music_function (sid))
703         {
704                 yylval.scm = get_music_function_transform (sid);
705                 
706                 return music_function_type (yylval.scm);
707         }
708
709         if (sid != SCM_UNDEFINED)
710         {
711                 yylval.scm = sid;
712                 return identifier_type (sid);
713         }
714
715         String msg (_f ("unknown escaped string: `\\%s'", str));        
716         LexerError (msg.to_str0 ());
717
718         yylval.scm = scm_makfrom0str (str.to_str0 ());
719
720         return STRING;
721 }
722
723 int
724 Lily_lexer::scan_bare_word (String str)
725 {
726         SCM sym = ly_symbol2scm (str.to_str0 ());
727         if ((YYSTATE == notes) || (YYSTATE == chords)) {
728                 SCM handle = SCM_BOOL_F;
729                 if (scm_is_pair (pitchname_tab_stack_))
730                         handle = scm_hashq_get_handle (scm_car (pitchname_tab_stack_), sym);
731                 
732                 if (scm_is_pair (handle)) {
733                         yylval.scm = scm_cdr (handle);
734                         if (unsmob_pitch (yylval.scm)) 
735                             return (YYSTATE == notes) ? NOTENAME_PITCH : TONICNAME_PITCH;
736                         else if (scm_is_symbol (yylval.scm))
737                             return DRUM_PITCH;
738                 }
739                 else if ((handle = scm_hashq_get_handle (chordmodifier_tab_, sym))!= SCM_BOOL_F)
740                 {
741                     yylval.scm = scm_cdr (handle);
742                     return CHORD_MODIFIER;
743                 }
744         }
745
746         yylval.scm = scm_makfrom0str (str.to_str0 ());
747         return STRING;
748 }
749
750 bool
751 Lily_lexer::is_note_state () const
752 {
753         return YY_START == notes;
754 }
755
756 bool
757 Lily_lexer::is_chord_state () const
758 {
759         return YY_START == chords;
760 }
761
762 bool
763 Lily_lexer::is_lyric_state () const
764 {
765         return YY_START == lyrics;
766 }
767
768 bool
769 Lily_lexer::is_figure_state () const
770 {
771         return YY_START == figures;
772 }
773
774 /*
775  urg, belong to String (_convert)
776  and should be generalised 
777  */
778 void
779 strip_leading_white (String&s)
780 {
781         int i=0;
782         for (;  i < s.length (); i++) 
783                 if (!isspace (s[i]))
784                         break;
785
786         s = s.nomid_string (0, i);
787 }
788
789 void
790 strip_trailing_white (String&s)
791 {
792         int i=s.length ();      
793         while (i--) 
794                 if (!isspace (s[i]))
795                         break;
796
797         s = s.left_string (i+1);
798 }
799
800
801
802 /* 2.1.2x something -> \property -> \set. */ 
803 Lilypond_version oldest_version ("2.3.22");
804
805
806 bool
807 is_valid_version (String s)
808 {
809   Lilypond_version current ( MAJOR_VERSION "." MINOR_VERSION "." PATCH_LEVEL );
810   Lilypond_version ver (s);
811   if (! ((ver >= oldest_version) && (ver <= current)))
812         {       
813                 non_fatal_error (_f ("Incorrect lilypond version: %s (%s, %s)", ver.to_string (), oldest_version.to_string (), current.to_string ()));
814                 non_fatal_error (_ ("Consider updating the input with the convert-ly script")); 
815                 return false;
816     }
817   return true;
818 }
819         
820
821 /*
822   substitute _ and \,
823 */
824 String
825 lyric_fudge (String s)
826 {
827   char  * chars  =s.get_copy_str0 ();
828
829   for (char * p = chars; *p ; p++)
830     {
831       if (*p == '_' && (p == chars || *(p-1) != '\\'))
832         *p = ' ';
833     }
834   
835   s = String (chars);
836   delete[] chars;
837
838   int i =0;     
839   if ((i=s.index ("\\,")) != -1)   // change "\," to TeX's "\c "
840     {
841       * (s.get_str0 () + i + 1) = 'c';
842       s = s.left_string (i+2) + " " + s.right_string (s.length ()-i-2);
843     }
844
845   return s;
846 }
847
848 /*
849 Convert "NUM/DEN" into a '(NUM . DEN) cons.
850 */
851 SCM
852 scan_fraction (String frac)
853 {
854         int i = frac.index ('/');
855         int l = frac.length ();
856         String left = frac.left_string (i);
857         String right = frac.right_string (l - i - 1);
858
859         int n = String_convert::dec2int (left);
860         int d = String_convert::dec2int (right);
861         return scm_cons (scm_int2num (n), scm_int2num (d));
862 }
863
864 // Breaks for flex 2.5.31
865 #if 0
866 /* avoid silly flex induced gcc warnings */
867 static void yy_push_state (int) {;}
868 static void yy_pop_state () {;}
869 static int yy_top_state () { return 0; }
870
871 static void
872 avoid_silly_flex_induced_gcc_warnings ()
873 {
874         (void)yy_start_stack_ptr;
875         (void)yy_start_stack_depth;
876         (void)yy_start_stack;
877         yy_push_state (0);
878         yy_pop_state ();
879         yy_top_state ();
880         avoid_silly_flex_induced_gcc_warnings ();
881 }
882 #endif
883
884 SCM
885 lookup_markup_command (String s)
886 {
887         SCM proc = ly_scheme_function ("lookup-markup-command");
888         return scm_call_1 (proc, scm_makfrom0str (s.to_str0 ()));
889 }
890
891
892 int
893 music_function_type (SCM func)
894 {
895         SCM type= scm_object_property (func, ly_symbol2scm ("music-function-signature-keyword"));
896         if (type == ly_symbol2scm ("scm"))
897         {
898                 return MUSIC_FUNCTION_SCM;
899         }
900         else if (type == ly_symbol2scm ("music"))
901         {
902                 return MUSIC_FUNCTION_MUSIC;
903         }
904         else if (type == ly_symbol2scm ("scm-music"))
905         {
906                 return MUSIC_FUNCTION_SCM_MUSIC;
907         }
908         else if (type == ly_symbol2scm ("scm-scm"))
909         {
910                 return MUSIC_FUNCTION_SCM_SCM;
911         }
912         else if (type == ly_symbol2scm ("music-music"))
913         {
914                 return MUSIC_FUNCTION_MUSIC_MUSIC;
915         }
916         else if (type == ly_symbol2scm ("scm-music-music"))
917         {
918                 return MUSIC_FUNCTION_SCM_MUSIC_MUSIC;
919         }
920         else if (type == ly_symbol2scm ("scm-scm-music"))
921         {
922                 return MUSIC_FUNCTION_SCM_SCM_MUSIC;
923         }
924         else if (type == ly_symbol2scm ("markup"))
925         {
926                 return MUSIC_FUNCTION_MARKUP;
927         }
928         else if (type == ly_symbol2scm ("markup-music"))
929         {
930                 return MUSIC_FUNCTION_MARKUP_MUSIC;
931         }
932         else if (type == ly_symbol2scm ("markup-markup"))
933         {
934                 return MUSIC_FUNCTION_MARKUP_MARKUP;
935         }
936         else if (type == ly_symbol2scm ("markup-music-music"))
937         {
938                 return MUSIC_FUNCTION_MARKUP_MUSIC_MUSIC;
939         }
940         else if (type == ly_symbol2scm ("markup-markup-music"))
941         {
942                 return MUSIC_FUNCTION_MARKUP_MARKUP_MUSIC;
943         }
944         else if (type == ly_symbol2scm ("noarg"))
945         {
946                 return MUSIC_FUNCTION;
947         }
948         else
949                 {
950                 /* TODO: print location */
951                 error ("Can not find signature for music function.");
952                 }
953
954         return MUSIC_FUNCTION_SCM;
955 }