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