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