]> git.donarmstrong.com Git - lilypond.git/blob - lily/lexer.ll
Issue 4550 (2/2) Avoid "using namespace std;" in included files
[lilypond.git] / lily / lexer.ll
1 %{ // -*- mode: c++; c-file-style: "linux"; indent-tabs-mode: t -*-
2 /*
3   This file is part of LilyPond, the GNU music typesetter.
4
5   Copyright (C) 1996--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
6                  Jan Nieuwenhuizen <janneke@gnu.org>
7
8   LilyPond is free software: you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation, either version 3 of the License, or
11   (at your option) any later version.
12
13   LilyPond is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /* Mode and indentation are at best a rough approximation based on TAB
23  * formatting (reasonable for compatibility with unspecific editor
24  * modes as Flex modes are hard to find) and need manual correction
25  * frequently.  Without a reasonably dependable way of formatting a
26  * Flex file sensibly, there is little point in trying to fix the
27  * inconsistent state of indentation.
28  */
29
30 /*
31   backup rules
32
33   after making a change to the lexer rules, run
34       flex -b <this lexer file>
35   and make sure that
36       lex.backup
37   contains no backup states, but only the reminder
38       Compressed tables always back up.
39  (don-t forget to rm lex.yy.cc :-)
40  */
41
42
43
44 #include <cstdio>
45 #include <cctype>
46 #include <cerrno>
47
48 /* Flex >= 2.5.29 fix; FlexLexer.h's multiple include bracing breaks
49    when building the actual lexer.  */
50
51 #define LEXER_CC
52
53 #include <iostream>
54
55 #include "context-def.hh"
56 #include "duration.hh"
57 #include "international.hh"
58 #include "interval.hh"
59 #include "lily-guile.hh"
60 #include "lily-lexer.hh"
61 #include "lily-parser.hh"
62 #include "lilypond-version.hh"
63 #include "main.hh"
64 #include "music.hh"
65 #include "music-function.hh"
66 #include "parse-scm.hh"
67 #include "parser.hh"
68 #include "pitch.hh"
69 #include "source-file.hh"
70 #include "std-string.hh"
71 #include "version.hh"
72 #include "warn.hh"
73 #include "lily-imports.hh"
74
75 using std::string;
76
77 /*
78 RH 7 fix (?)
79 */
80 #define isatty HORRIBLEKLUDGE
81
82 void strip_trailing_white (string&);
83 void strip_leading_white (string&);
84 string lyric_fudge (string s);
85 SCM lookup_markup_command (string s);
86 SCM lookup_markup_list_command (string s);
87 bool is_valid_version (string s);
88
89
90 #define start_quote() do {                      \
91                 yy_push_state (quote);          \
92                 yylval = SCM_EOL;               \
93         } while (0)
94
95 /*
96   The inside of \"violin1" is marked by commandquote mode
97 */
98
99 #define start_command_quote() do {              \
100                 yy_push_state (commandquote);   \
101                 yylval = SCM_EOL;               \
102         } while (0)
103
104 #define yylval (*lexval_)
105
106 #define yylloc (*lexloc_)
107
108 #define YY_USER_ACTION  add_lexed_char (YYLeng ());
109
110
111 SCM scan_fraction (string);
112 SCM (* scm_parse_error_handler) (void *);
113
114
115
116 %}
117
118 %option c++
119 %option noyywrap
120 %option nodefault
121 %option debug
122 %option yyclass="Lily_lexer"
123 %option stack
124 %option never-interactive
125 %option warn
126
127 %x chords
128 %x figures
129 %x incl
130 %x lyrics
131 %x longcomment
132 %x maininput
133 %x markup
134 %x notes
135 %x quote
136 %x commandquote
137 %x sourcefileline
138 %x sourcefilename
139 %x version
140
141 /* The strategy concerning multibyte characters is to accept them but
142  * call YYText_utf8 for patterns that might contain them, in order to
143  * get a single code path responsible for flagging non-UTF-8 input:
144  * Patterns for accepting only valid UTF-8 without backing up are
145  * really hard to do and complex, and if nice error messages are
146  * wanted, one would need patterns catching the invalid input as well.
147  *
148  * Since editors and operating environments don't necessarily behave
149  * reasonably in the presence of mixed encodings, we flag encoding
150  * errors also in identifiers, comments, and strings where it would be
151  * conceivable to just transparently work with the byte string.  But
152  * the whole point of caring about UTF-8 in here at all is too avoid
153  * stranger errors later when input passes into backends or log files
154  * or console output or error messages.
155  */
156
157 A               [a-zA-Z\200-\377]
158 AA              {A}|_
159 N               [0-9]
160 ANY_CHAR        (.|\n)
161 WORD            {A}([-_]{A}|{A})*
162 COMMAND         \\{WORD}
163 /* SPECIAL category is for every letter that needs to get passed to
164  * the parser rather than being redefinable by the user */
165 SPECIAL         [-+*/=<>{}!?_^'',.:]
166 SHORTHAND       (.|\\.)
167 UNSIGNED        {N}+
168 E_UNSIGNED      \\{N}+
169 FRACTION        {N}+\/{N}+
170 INT             -?{UNSIGNED}
171 REAL            ({INT}\.{N}*)|(-?\.{N}+)
172 STRICTREAL      {UNSIGNED}\.{UNSIGNED}
173 WHITE           [ \n\t\f\r]
174 HORIZONTALWHITE         [ \t]
175 BLACK           [^ \n\t\f\r]
176 RESTNAME        [rs]
177 ESCAPED         [nt\\''""]
178 EXTENDER        __
179 HYPHEN          --
180 BOM_UTF8        \357\273\277
181
182 %%
183
184
185 <*>\r           {
186         // swallow and ignore carriage returns
187 }
188
189    /* Use the trailing context feature. Otherwise, the BOM will not be
190       found if the file starts with an identifier definition. */
191 <INITIAL,chords,lyrics,figures,notes>{BOM_UTF8}/.* {
192   if (lexloc_->line_number () != 1 || lexloc_->column_number () != 0)
193     {
194       LexerWarning (_ ("stray UTF-8 BOM encountered").c_str ());
195       // exit (1);
196     }
197   debug_output (_ ("Skipping UTF-8 BOM"));
198 }
199
200 <INITIAL,chords,figures,incl,lyrics,markup,notes>{
201   "%{"  {
202         yy_push_state (longcomment);
203   }
204   %[^{\n\r][^\n\r]*[\n\r]?      {
205           (void) YYText_utf8 ();
206   }
207   %[\n\r]?      {
208   }
209   {WHITE}+      {
210
211   }
212 }
213
214 <INITIAL,notes,figures,chords,markup>{
215         \"              {
216                 start_quote ();
217         }
218 }
219
220 <INITIAL,chords,lyrics,notes,figures>\\version{WHITE}*  {
221         yy_push_state (version);
222 }
223 <INITIAL,chords,lyrics,notes,figures>\\sourcefilename{WHITE}*   {
224         yy_push_state (sourcefilename);
225 }
226 <INITIAL,chords,lyrics,notes,figures>\\sourcefileline{WHITE}*   {
227         yy_push_state (sourcefileline);
228 }
229 <version>\"[^""]*\"     { /* got the version number */
230         string s (YYText_utf8 () + 1);
231         s = s.substr (0, s.rfind ('\"'));
232
233         yy_pop_state ();
234
235         SCM top_scope = scm_car (scm_last_pair (scopes_));
236         scm_module_define (top_scope, ly_symbol2scm ("version-seen"), SCM_BOOL_T);
237
238         if (!is_valid_version (s)) {
239                 yylval = SCM_UNSPECIFIED;
240                 return INVALID;
241         }
242 }
243 <sourcefilename>\"[^""]*\"     {
244         string s (YYText_utf8 () + 1);
245         s = s.substr (0, s.rfind ('\"'));
246
247         yy_pop_state ();
248         here_input().get_source_file ()->name_ = s;
249         message (_f ("Renaming input to: `%s'", s.c_str ()));
250         progress_indication ("\n");
251         scm_module_define (scm_car (scopes_),
252                      ly_symbol2scm ("input-file-name"),
253                      ly_string2scm (s));
254
255 }
256
257 <sourcefileline>{INT}   {
258         int i;
259         sscanf (YYText (), "%d", &i);
260
261         yy_pop_state ();
262         here_input ().get_source_file ()->set_line (here_input ().start (), i);
263 }
264
265 <version>{ANY_CHAR}     {
266         LexerError (_ ("quoted string expected after \\version").c_str ());
267         yy_pop_state ();
268 }
269 <sourcefilename>{ANY_CHAR}      {
270         LexerError (_ ("quoted string expected after \\sourcefilename").c_str ());
271         yy_pop_state ();
272 }
273 <sourcefileline>{ANY_CHAR}      {
274         LexerError (_ ("integer expected after \\sourcefileline").c_str ());
275         yy_pop_state ();
276 }
277 <longcomment>{
278         [^\%]*          {
279                 (void) YYText_utf8 ();
280         }
281         \%*[^}%]*               {
282                 (void) YYText_utf8 ();
283         }
284         "%"+"}"         {
285                 yy_pop_state ();
286         }
287 }
288
289
290 <INITIAL,chords,lyrics,notes,figures>\\maininput           {
291         if (!is_main_input_)
292         {
293                 start_main_input ();
294                 main_input_level_ = include_stack_.size ();
295                 is_main_input_ = true;
296                 int state = YYSTATE;
297                 yy_push_state (maininput);
298                 yy_push_state (state);
299         }
300         else
301                 LexerError (_ ("\\maininput not allowed outside init files").c_str ());
302 }
303
304 <INITIAL,chords,lyrics,figures,notes>\\include           {
305         yy_push_state (incl);
306 }
307 <incl>\"[^""]*\"   { /* got the include file name */
308         string s (YYText_utf8 ()+1);
309         s = s.substr (0, s.rfind ('"'));
310
311         new_input (s, sources_);
312         yy_pop_state ();
313 }
314 <incl>\\{BLACK}*{WHITE}? { /* got the include identifier */
315         string s = YYText_utf8 () + 1;
316         strip_trailing_white (s);
317         if (s.length () && (s[s.length () - 1] == ';'))
318           s = s.substr (0, s.length () - 1);
319
320         SCM sid = lookup_identifier (s);
321         if (scm_is_string (sid)) {
322                 new_input (ly_scm2string (sid), sources_);
323                 yy_pop_state ();
324         } else {
325             string msg (_f ("wrong or undefined identifier: `%s'", s ));
326
327             LexerError (msg.c_str ());
328             SCM err = scm_current_error_port ();
329             scm_puts ("This value was found in the table: ", err);
330             scm_display (sid, err);
331           }
332 }
333 <incl>(\$|#) { // scm for the filename
334         Input hi = here_input();
335         hi.step_forward ();
336         SCM sval = ly_parse_scm (hi, be_safe_global && is_main_input_, parser_);
337         sval = eval_scm (sval, hi);
338         int n = hi.end () - hi.start ();
339
340         for (int i = 0; i < n; i++)
341         {
342                 yyinput ();
343         }
344         char_count_stack_.back () += n;
345
346         if (scm_is_string (sval)) {
347                 new_input (ly_scm2string (sval), sources_);
348                 yy_pop_state ();
349         } else {
350                 LexerError (_ ("string expected after \\include").c_str ());
351                 if (!SCM_UNBNDP (sval)) {
352                         SCM err = scm_current_error_port ();
353                         scm_puts ("This value was found instead: ", err);
354                         scm_display (sval, err);
355                 }
356         }
357 }
358
359 <incl,version,sourcefilename>\"[^""]*   { // backup rule
360         LexerError (_ ("end quote missing").c_str ());
361         yy_pop_state ();
362 }
363
364     /* Flex picks the longest matching pattern including trailing
365      * contexts.  Without the backup pattern, r-. does not trigger the
366      * {RESTNAME} rule but rather the {WORD}/[-_] rule coming later,
367      * needed for avoiding backup states.
368      */
369
370 <chords,notes,figures>{RESTNAME}/[-_]   |  // pseudo backup rule
371 <chords,notes,figures>{RESTNAME}        {
372         char const *s = YYText ();
373         yylval = scm_from_ascii_string (s);
374         return RESTNAME;
375 }
376 <chords,notes,figures>q/[-_]    | // pseudo backup rule
377 <chords,notes,figures>q {
378         yylval = SCM_UNSPECIFIED;
379         return CHORD_REPETITION;
380 }
381
382 <chords,notes,figures>R/[-_]    | // pseudo backup rule
383 <chords,notes,figures>R         {
384         yylval = SCM_UNSPECIFIED;
385         return MULTI_MEASURE_REST;
386 }
387 <INITIAL,chords,figures,lyrics,markup,notes>#   { //embedded scm
388         Input hi = here_input();
389         hi.step_forward ();
390         SCM sval = ly_parse_scm (hi, be_safe_global && is_main_input_, parser_);
391
392         if (SCM_UNBNDP (sval))
393                 error_level_ = 1;
394
395         int n = hi.end () - hi.start ();
396         for (int i = 0; i < n; i++)
397         {
398                 yyinput ();
399         }
400         char_count_stack_.back () += n;
401
402         yylval = sval;
403         return SCM_TOKEN;
404 }
405
406 <INITIAL,chords,figures,lyrics,markup,notes>\$  { //immediate scm
407         Input hi = here_input();
408         hi.step_forward ();
409         SCM sval = ly_parse_scm (hi, be_safe_global && is_main_input_, parser_);
410
411         int n = hi.end () - hi.start ();
412
413         for (int i = 0; i < n; i++)
414         {
415                 yyinput ();
416         }
417         char_count_stack_.back () += n;
418
419         sval = eval_scm (sval, hi, '$');
420
421         int token = scan_scm_id (sval);
422         if (!scm_is_eq (yylval, SCM_UNSPECIFIED))
423                 return token;
424 }
425
426 <INITIAL,notes,lyrics,chords>{
427         \<\<    {
428                 yylval = SCM_UNSPECIFIED;
429                 return DOUBLE_ANGLE_OPEN;
430         }
431         \>\>    {
432                 yylval = SCM_UNSPECIFIED;
433                 return DOUBLE_ANGLE_CLOSE;
434         }
435 }
436
437 <INITIAL,notes,chords>{
438         \<      {
439                 yylval = SCM_UNSPECIFIED;
440                 return ANGLE_OPEN;
441         }
442         \>      {
443                 yylval = SCM_UNSPECIFIED;
444                 return ANGLE_CLOSE;
445         }
446 }
447
448 <figures>{
449         _       {
450                 yylval = SCM_UNSPECIFIED;
451                 return FIGURE_SPACE;
452         }
453         \>              {
454                 yylval = SCM_UNSPECIFIED;
455                 return FIGURE_CLOSE;
456         }
457         \<      {
458                 yylval = SCM_UNSPECIFIED;
459                 return FIGURE_OPEN;
460         }
461         \\\+    {
462                 yylval = SCM_UNSPECIFIED;
463                 return E_PLUS;
464         }
465         \\!     {
466                 yylval = SCM_UNSPECIFIED;
467                 return E_EXCLAMATION;
468         }
469         \\\\    {
470                 yylval = SCM_UNSPECIFIED;
471                 return E_BACKSLASH;
472         }
473         [][]    {
474                 yylval = SCM_UNSPECIFIED;
475                 return  YYText ()[0];
476         }
477 }
478
479 <notes,figures>{
480         {WORD}/[-_]     | // backup rule
481         {WORD}  {
482                 return scan_bare_word (YYText_utf8 ());
483         }
484         \\\"    {
485                 start_command_quote ();
486         }
487         {COMMAND}/[-_]  | // backup rule
488         {COMMAND}       {
489                 return scan_escaped_word (YYText_utf8 () + 1); 
490         }
491         {FRACTION}      {
492                 yylval =  scan_fraction (YYText ());
493                 return FRACTION;
494         }
495         {STRICTREAL}    {
496                 yylval = scm_c_read_string (YYText ());
497                 return REAL;
498         }
499         {UNSIGNED}/[/.] | // backup rule
500         {UNSIGNED}      {
501                 yylval = scm_c_read_string (YYText ());
502                 return UNSIGNED;
503         }
504         {E_UNSIGNED}    {
505                 yylval = scm_c_read_string (YYText () + 1);
506                 return E_UNSIGNED;
507         }
508 }
509
510 <quote,commandquote>{
511         \\{ESCAPED}     {
512                 char c = escaped_char (YYText ()[1]);
513                 yylval = scm_cons (scm_from_ascii_stringn (&c, 1),
514                                    yylval);
515         }
516         [^\\""]+        {
517                 yylval = scm_cons (scm_from_utf8_string (YYText_utf8 ()),
518                                    yylval);
519         }
520         \"      {
521
522                 /* yylval is union. Must remember STRING before setting SCM*/
523
524                 yylval = scm_string_concatenate_reverse (yylval,
525                                                          SCM_UNDEFINED,
526                                                          SCM_UNDEFINED);
527
528                 if (get_state () == commandquote) {
529                         yy_pop_state ();
530                         return scan_escaped_word (ly_scm2string (yylval));
531                 }
532
533                 yy_pop_state ();
534
535                 return STRING;
536         }
537         \\      {
538                 yylval = scm_cons (scm_from_ascii_string (YYText ()),
539                                    yylval);
540         }
541 }
542
543 <lyrics>{
544         \" {
545                 start_quote ();
546         }
547         {FRACTION}      {
548                 yylval =  scan_fraction (YYText ());
549                 return FRACTION;
550         }
551         {STRICTREAL}    {
552                 yylval = scm_c_read_string (YYText ());
553                 return REAL;
554         }
555         {UNSIGNED}/[/.] | // backup rule
556         {UNSIGNED}              {
557                 yylval = scm_c_read_string (YYText ());
558                 return UNSIGNED;
559         }
560         \\\"    {
561                 start_command_quote ();
562         }
563         {COMMAND}/[-_]  | // backup rule
564         {COMMAND}       {
565                 return scan_escaped_word (YYText_utf8 () + 1);
566         }
567         \\.|\|  {
568                 // UTF-8 already covered by COMMAND
569                 return scan_shorthand (YYText ());
570         }
571         /* Characters needed to express durations, assignments */
572         [*.=]   {
573                 yylval = SCM_UNSPECIFIED;
574                 return YYText ()[0];
575         }
576         [^|*.=$#{}\"\\ \t\n\r\f0-9][^$#{}\"\\ \t\n\r\f0-9]* {
577                 /* ugr. This sux. */
578                 string s (YYText_utf8 ());
579                 yylval = SCM_UNSPECIFIED;
580                 if (s == "__")
581                         return EXTENDER;
582                 if (s == "--")
583                         return HYPHEN;
584                 s = lyric_fudge (s);
585                 yylval = ly_string2scm (s);
586
587                 return STRING;
588         }
589         /* This should really just cover {} */
590         [{}] {
591                 yylval = SCM_UNSPECIFIED;
592                 return YYText ()[0];
593         }
594 }
595 <chords>{
596         {WORD}/[-_]     | // backup rule
597         {WORD}  {
598                 return scan_bare_word (YYText_utf8 ());
599         }
600         \\\"    {
601                 start_command_quote ();
602         }
603         {COMMAND}/[-_]  | // backup rule
604         {COMMAND}       {
605                 return scan_escaped_word (YYText_utf8 () + 1);
606         }
607         {FRACTION}      {
608                 yylval =  scan_fraction (YYText ());
609                 return FRACTION;
610         }
611         {UNSIGNED}/\/   | // backup rule
612         {UNSIGNED}              {
613                 yylval = scm_c_read_string (YYText ());
614                 return UNSIGNED;
615         }
616         -  {
617                 yylval = SCM_UNSPECIFIED;
618                 return CHORD_MINUS;
619         }
620         :  {
621                 yylval = SCM_UNSPECIFIED;
622                 return CHORD_COLON;
623         }
624         \/\+ {
625                 yylval = SCM_UNSPECIFIED;
626                 return CHORD_BASS;
627         }
628         \/  {
629                 yylval = SCM_UNSPECIFIED;
630                 return CHORD_SLASH;
631         }
632         \^  {
633                 yylval = SCM_UNSPECIFIED;
634                 return CHORD_CARET;
635         }
636 }
637
638
639 <markup>{
640         \\score {
641                 yylval = SCM_UNSPECIFIED;
642                 return SCORE;
643         }
644         \\score-lines {
645                 yylval = SCM_UNSPECIFIED;
646                 return SCORELINES;
647         }
648         \\\"    {
649                 start_command_quote ();
650         }
651         {COMMAND}/[-_]  | // backup rule
652         {COMMAND} {
653                 string str (YYText_utf8 () + 1);
654
655                 int token_type = MARKUP_FUNCTION;
656                 SCM s = lookup_markup_command (str);
657
658                 // lookup-markup-command returns a pair with the car
659                 // being the function to call, and the cdr being the
660                 // call signature specified to define-markup-command,
661                 // a list of predicates.
662
663                 if (!scm_is_pair (s)) {
664                   // If lookup-markup-command was not successful, we
665                   // try lookup-markup-list-command instead.
666                   // If this fails as well, we just scan and return
667                   // the escaped word.
668                   s = lookup_markup_list_command (str);
669                   if (scm_is_pair (s))
670                     token_type = MARKUP_LIST_FUNCTION;
671                   else
672                     return scan_escaped_word (str);
673                 }
674
675                 // If the list of predicates is, say,
676                 // (number? number? markup?), then tokens
677                 // EXPECT_MARKUP EXPECT_SCM EXPECT_SCM EXPECT_NO_MORE_ARGS
678                 // will be generated.  Note that we have to push them
679                 // in reverse order, so the first token pushed in the
680                 // loop will be EXPECT_NO_MORE_ARGS.
681
682                 yylval = scm_car(s);
683
684                 // yylval now contains the function to call as token
685                 // value (for token type MARKUP_FUNCTION or
686                 // MARKUP_LIST_FUNCTION).
687
688                 push_extra_token (here_input (), EXPECT_NO_MORE_ARGS);
689                 s = scm_cdr(s);
690                 for (; scm_is_pair(s); s = scm_cdr(s)) {
691                   SCM predicate = scm_car(s);
692
693                   if (predicate == Lily::markup_list_p)
694                     push_extra_token (here_input (), EXPECT_MARKUP_LIST);
695                   else if (predicate == Lily::markup_p)
696                     push_extra_token (here_input (), EXPECT_MARKUP);
697                   else
698                     push_extra_token (here_input (), EXPECT_SCM, predicate);
699                 }
700                 return token_type;
701         }
702         [^$#{}\"\\ \t\n\r\f]+ {
703                 string s (YYText_utf8 ()); 
704
705                 yylval = ly_string2scm (s);
706                 return STRING;
707         }
708         [{}]  {
709                 yylval = SCM_UNSPECIFIED;
710                 return YYText ()[0];
711         }
712 }
713
714 <longcomment><<EOF>> {
715                 LexerError (_ ("EOF found inside a comment").c_str ());
716                 yy_pop_state ();
717         }
718
719 <quote,commandquote><<EOF>> {
720         LexerError (_ ("EOF found inside string").c_str ());
721         yy_pop_state ();
722 }
723
724 <<EOF>> {
725         yylval = SCM_UNSPECIFIED;
726         if (is_main_input_)
727         {
728                 is_main_input_ = include_stack_.size () > main_input_level_;
729                 if (!is_main_input_)
730                 {
731                         main_input_level_ = 0;
732                         pop_state ();
733                         if (YYSTATE != maininput)
734                         {
735                                 LexerError (_ ("Unfinished main input").c_str ());
736                                 do {
737                                         yy_pop_state ();
738                                 } while (YYSTATE != maininput);
739                         }
740                         extra_tokens_ = SCM_EOL;
741                         yy_pop_state ();
742                 }
743                 if (!close_input () || !is_main_input_)
744                 /* Returns YY_NULL */
745                         yyterminate ();
746         }
747         else if (!close_input ())
748                 /* Returns YY_NULL */
749                 yyterminate ();
750 }
751
752 <maininput>{ANY_CHAR} {
753         while (include_stack_.size () > main_input_level_
754                && close_input ())
755                 ;
756         yyterminate ();
757 }
758
759 <INITIAL>{
760         {WORD}/[-_]     | // backup rule
761         {WORD}  {
762                 return scan_bare_word (YYText_utf8 ());
763         }
764         \\\"    {
765                 start_command_quote ();
766         }
767         {COMMAND}/[-_]  | // backup rule
768         {COMMAND}       {
769                 return scan_escaped_word (YYText_utf8 () + 1);
770         }
771 }
772
773 {FRACTION}      {
774         yylval =  scan_fraction (YYText ());
775         return FRACTION;
776 }
777
778 -{UNSIGNED}     | // backup rule
779 {REAL}          {
780         yylval = scm_c_read_string (YYText ());
781         return REAL;
782 }
783
784 {UNSIGNED}/\/   | // backup rule
785 {UNSIGNED}      {
786         yylval = scm_c_read_string (YYText ());
787         return UNSIGNED;
788 }
789
790
791 -/\.    { // backup rule
792         yylval = SCM_UNSPECIFIED;
793         return YYText ()[0];
794 }
795
796 <INITIAL,chords,lyrics,figures,notes>{SPECIAL}  {
797         yylval = SCM_UNSPECIFIED;
798         return YYText ()[0];
799 }
800
801 <INITIAL,chords,lyrics,figures,notes>{SHORTHAND}        {
802         return scan_shorthand (YYText_utf8 ()); // should not be utf-8
803 }
804
805 <*>.[\200-\277]*        {
806         string msg = _f ("invalid character: `%s'", YYText_utf8 ());
807         LexerError (msg.c_str ());
808         yylval = SCM_UNSPECIFIED;
809         return '%';  // Better not return half a utf8 character.
810 }
811
812 %%
813
814 /* Make the lexer generate a token of the given type as the next token.
815  TODO: make it possible to define a value for the token as well */
816 void
817 Lily_lexer::push_extra_token (Input const &where, int token_type, SCM scm)
818 {
819         extra_tokens_ = scm_cons (scm_cons2 (where.smobbed_copy (),
820                                              scm_from_int (token_type),
821                                              scm), extra_tokens_);
822 }
823
824 int
825 Lily_lexer::pop_extra_token ()
826 {
827         if (scm_is_null (extra_tokens_))
828                 return -1;
829
830   /* produce requested token */
831         yylloc = *unsmob<Input> (scm_caar (extra_tokens_));
832         int type = scm_to_int (scm_cadar (extra_tokens_));
833         yylval = scm_cddar (extra_tokens_);
834         extra_tokens_ = scm_cdr (extra_tokens_);
835         return type;
836 }
837
838 void
839 Lily_lexer::push_chord_state (SCM alist)
840 {
841         SCM p = scm_assq (alist, pitchname_tab_stack_);
842
843         if (scm_is_false (p))
844                 p = scm_cons (alist, alist_to_hashq (alist));
845         pitchname_tab_stack_ = scm_cons (p, pitchname_tab_stack_);
846         yy_push_state (chords);
847 }
848
849 void
850 Lily_lexer::push_figuredbass_state ()
851 {
852         yy_push_state (figures);
853 }
854
855 void
856 Lily_lexer::push_initial_state ()
857 {
858         yy_push_state (INITIAL);
859 }
860
861 void
862 Lily_lexer::push_lyric_state ()
863 {
864         yy_push_state (lyrics);
865 }
866
867 void
868 Lily_lexer::push_markup_state ()
869 {
870         yy_push_state (markup);
871 }
872
873 void
874 Lily_lexer::push_note_state (SCM alist)
875 {
876         SCM p = scm_assq (alist, pitchname_tab_stack_);
877
878         if (scm_is_false (p))
879                 p = scm_cons (alist, alist_to_hashq (alist));
880         pitchname_tab_stack_ = scm_cons (p, pitchname_tab_stack_);
881         yy_push_state (notes);
882 }
883
884 void
885 Lily_lexer::pop_state ()
886 {
887         if (YYSTATE == notes || YYSTATE == chords)
888                 pitchname_tab_stack_ = scm_cdr (pitchname_tab_stack_);
889
890         // don't cross the maininput threshold
891         if (YYSTATE != maininput)
892                 yy_pop_state ();
893
894 }
895
896 int
897 Lily_lexer::identifier_type (SCM sid)
898 {
899         int k = try_special_identifiers (&yylval , sid);
900         return k >= 0  ? k : SCM_IDENTIFIER;
901 }
902
903
904 int
905 Lily_lexer::scan_escaped_word (const string &str)
906 {
907         // use more SCM for this.
908
909 //      SCM sym = ly_symbol2scm (str.c_str ());
910
911         yylval = SCM_UNSPECIFIED;
912         int i = lookup_keyword (str);
913
914         if (i != -1)
915                 return i;
916
917         SCM sid = lookup_identifier (str);
918         if (Music *m = unsmob<Music> (sid))
919         {
920                 m->set_spot (override_input (here_input ()));
921         }
922
923         if (!SCM_UNBNDP (sid))
924                 return scan_scm_id (sid);
925
926         string msg (_f ("unknown escaped string: `\\%s'", str));
927         LexerError (msg.c_str ());
928
929         yylval = ly_string2scm (str);
930
931         return STRING;
932 }
933
934 int
935 Lily_lexer::scan_shorthand (const string &str)
936 {
937         SCM sid = lookup_identifier (str);
938         if (Music *m = unsmob<Music> (sid))
939         {
940                 m->set_spot (override_input (here_input ()));
941         }
942
943         if (!SCM_UNBNDP (sid))
944                 return scan_scm_id (sid);
945
946         string msg (_f ("undefined character or shorthand: %s", str));
947         LexerError (msg.c_str ());
948
949         yylval = ly_string2scm (str);
950
951         return STRING;
952 }
953
954 int
955 Lily_lexer::scan_scm_id (SCM sid)
956 {
957         if (Music_function *fun = unsmob<Music_function> (sid))
958         {
959                 int funtype = SCM_FUNCTION;
960
961                 yylval = sid;
962
963                 SCM s = fun->get_signature ();
964                 SCM cs = scm_car (s);
965
966                 if (scm_is_pair (cs))
967                 {
968                         cs = SCM_CAR (cs);
969                 }
970
971                 if (scm_is_eq (cs, Lily::ly_music_p))
972                         funtype = MUSIC_FUNCTION;
973                 else if (scm_is_eq (cs, Lily::ly_event_p))
974                         funtype = EVENT_FUNCTION;
975                 else if (ly_is_procedure (cs))
976                         funtype = SCM_FUNCTION;
977                 else programming_error ("Bad syntax function predicate");
978
979                 push_extra_token (here_input (), EXPECT_NO_MORE_ARGS);
980                 for (s = scm_cdr (s); scm_is_pair (s); s = scm_cdr (s))
981                 {
982                         SCM optional = SCM_UNDEFINED;
983                         cs = scm_car (s);
984
985                         if (scm_is_pair (cs))
986                         {
987                                 optional = SCM_CDR (cs);
988                                 cs = SCM_CAR (cs);
989                         }
990
991                         if (ly_is_procedure (cs))
992                                 push_extra_token (here_input (), EXPECT_SCM, cs);
993                         else
994                         {
995                                 programming_error ("Function parameter without type-checking predicate");
996                                 continue;
997                         }
998                         if (!scm_is_eq (optional, SCM_UNDEFINED))
999                                 push_extra_token (here_input (), EXPECT_OPTIONAL, optional);
1000                 }
1001                 return funtype;
1002         }
1003         yylval = sid;
1004         return identifier_type (sid);
1005 }
1006
1007 int
1008 Lily_lexer::scan_bare_word (const string &str)
1009 {
1010         SCM sym = ly_symbol2scm (str.c_str ());
1011         if ((YYSTATE == notes) || (YYSTATE == chords)) {
1012                 SCM handle = SCM_BOOL_F;
1013                 if (scm_is_pair (pitchname_tab_stack_))
1014                         handle = scm_hashq_get_handle (scm_cdar (pitchname_tab_stack_), sym);
1015
1016                 if (scm_is_pair (handle)) {
1017                         yylval = scm_cdr (handle);
1018                         if (unsmob<Pitch> (yylval))
1019                             return (YYSTATE == notes) ? NOTENAME_PITCH : TONICNAME_PITCH;
1020                         else if (scm_is_symbol (yylval))
1021                             return DRUM_PITCH;
1022                 }
1023                 else if ((YYSTATE == chords)
1024                         && scm_is_true (handle = scm_hashq_get_handle (chordmodifier_tab_, sym)))
1025                 {
1026                     yylval = scm_cdr (handle);
1027                     return CHORD_MODIFIER;
1028                 }
1029         }
1030         yylval = ly_string2scm (str);
1031         return STRING;
1032 }
1033
1034 int
1035 Lily_lexer::get_state () const
1036 {
1037         return YY_START;
1038 }
1039
1040 bool
1041 Lily_lexer::is_note_state () const
1042 {
1043         return get_state () == notes;
1044 }
1045
1046 bool
1047 Lily_lexer::is_chord_state () const
1048 {
1049         return get_state () == chords;
1050 }
1051
1052 bool
1053 Lily_lexer::is_lyric_state () const
1054 {
1055         return get_state () == lyrics;
1056 }
1057
1058 bool
1059 Lily_lexer::is_figure_state () const
1060 {
1061         return get_state () == figures;
1062 }
1063
1064 // The extra_token parameter specifies how to convert multiple values
1065 // into additional tokens.  For '#', additional values get pushed as
1066 // SCM_IDENTIFIER.  For '$', they get checked for their type and get
1067 // pushed as a corresponding *_IDENTIFIER token.  Since the latter
1068 // tampers with yylval, it can only be done from the lexer itself, so
1069 // this function is private.
1070
1071 SCM
1072 Lily_lexer::eval_scm (SCM readerdata, Input hi, char extra_token)
1073 {
1074         SCM sval = SCM_UNDEFINED;
1075
1076         if (!SCM_UNBNDP (readerdata))
1077         {
1078                 sval = ly_eval_scm (readerdata,
1079                                     hi,
1080                                     be_safe_global && is_main_input_,
1081                                     parser_);
1082         }
1083
1084         if (SCM_UNBNDP (sval))
1085         {
1086                 error_level_ = 1;
1087                 return SCM_UNSPECIFIED;
1088         }
1089
1090         if (extra_token && SCM_VALUESP (sval))
1091         {
1092                 sval = scm_struct_ref (sval, SCM_INUM0);
1093
1094                 if (scm_is_pair (sval)) {
1095                         for (SCM p = scm_reverse (scm_cdr (sval));
1096                              scm_is_pair (p);
1097                              p = scm_cdr (p))
1098                         {
1099                                 SCM v = scm_car (p);
1100                                 if (Music *m = unsmob<Music> (v))
1101                                 {
1102                                         if (!unsmob<Input> (m->get_property ("origin")))
1103                                                 m->set_spot (override_input (here_input ()));
1104                                 }
1105
1106                                 int token;
1107                                 switch (extra_token) {
1108                                 case '$':
1109                                         token = scan_scm_id (v);
1110                                         if (!scm_is_eq (yylval, SCM_UNSPECIFIED))
1111                                                 push_extra_token (here_input (),
1112                                                                   token, yylval);
1113                                         break;
1114                                 case '#':
1115                                         push_extra_token (here_input (),
1116                                                           SCM_IDENTIFIER, v);
1117                                         break;
1118                                 }
1119                         }
1120                         sval = scm_car (sval);
1121                 } else
1122                         sval = SCM_UNSPECIFIED;
1123         }
1124
1125         if (Music *m = unsmob<Music> (sval))
1126         {
1127                 if (!unsmob<Input> (m->get_property ("origin")))
1128                         m->set_spot (override_input (here_input ()));
1129         }
1130
1131         return sval;
1132 }
1133
1134 /* Check for valid UTF-8 that has no overlong or surrogate codes and
1135    is in the range 0-0x10ffff */
1136
1137 const char *
1138 Lily_lexer::YYText_utf8 ()
1139 {
1140         const char * const p =  YYText ();
1141         for (int i=0; p[i];) {
1142                 if ((p[i] & 0xff) < 0x80) {
1143                         ++i;
1144                         continue;
1145                 }
1146                 int oldi = i; // start of character
1147                 int more = 0; // # of followup bytes, 0 if bad
1148                 switch (p[i++] & 0xff) {
1149                         // 0xc0 and 0xc1 are overlong prefixes for
1150                         // 0x00-0x3f and 0x40-0x7f respectively, bad.
1151                 case 0xc2:      // 0x80-0xbf
1152                 case 0xc3:      // 0xc0-0xff
1153                 case 0xc4:      // 0x100-0x13f
1154                 case 0xc5:      // 0x140-0x17f
1155                 case 0xc6:      // 0x180-0x1bf
1156                 case 0xc7:      // 0x1c0-0x1ff
1157                 case 0xc8:      // 0x200-0x23f
1158                 case 0xc9:      // 0x240-0x27f
1159                 case 0xca:      // 0x280-0x2bf
1160                 case 0xcb:      // 0x2c0-0x2ff
1161                 case 0xcc:      // 0x300-0x33f
1162                 case 0xcd:      // 0x340-0x37f
1163                 case 0xce:      // 0x380-0x3bf
1164                 case 0xcf:      // 0x3c0-0x3ff
1165                 case 0xd0:      // 0x400-0x43f
1166                 case 0xd1:      // 0x440-0x47f
1167                 case 0xd2:      // 0x480-0x4bf
1168                 case 0xd3:      // 0x4c0-0x4ff
1169                 case 0xd4:      // 0x500-0x53f
1170                 case 0xd5:      // 0x540-0x57f
1171                 case 0xd6:      // 0x580-0x5bf
1172                 case 0xd7:      // 0x5c0-0x5ff
1173                 case 0xd8:      // 0x600-0x63f
1174                 case 0xd9:      // 0x640-0x67f
1175                 case 0xda:      // 0x680-0x6bf
1176                 case 0xdb:      // 0x6c0-0x6ff
1177                 case 0xdc:      // 0x700-0x73f
1178                 case 0xdd:      // 0x740-0x77f
1179                 case 0xde:      // 0x780-0x7bf
1180                 case 0xdf:      // 0x7c0-0x7ff
1181                         more = 1; // 2-byte sequences, 0x80-0x7ff
1182                         break;
1183                 case 0xe0:
1184                         // don't allow overlong sequences for 0-0x7ff
1185                         if ((p[i] & 0xff) < 0xa0)
1186                                 break;
1187                 case 0xe1:      // 0x1000-0x1fff
1188                 case 0xe2:      // 0x2000-0x2fff
1189                 case 0xe3:      // 0x3000-0x3fff
1190                 case 0xe4:      // 0x4000-0x4fff
1191                 case 0xe5:      // 0x5000-0x5fff
1192                 case 0xe6:      // 0x6000-0x6fff
1193                 case 0xe7:      // 0x7000-0x7fff
1194                 case 0xe8:      // 0x8000-0x8fff
1195                 case 0xe9:      // 0x9000-0x9fff
1196                 case 0xea:      // 0xa000-0xafff
1197                 case 0xeb:      // 0xb000-0xbfff
1198                 case 0xec:      // 0xc000-0xcfff
1199                         more = 2; // 3-byte sequences, 0x7ff-0xcfff
1200                         break;
1201                 case 0xed:      // 0xd000-0xdfff
1202                         // Don't allow surrogate codes 0xd800-0xdfff
1203                         if ((p[i] & 0xff) >= 0xa0)
1204                                 break;
1205                 case 0xee:      // 0xe000-0xefff
1206                 case 0xef:      // 0xf000-0xffff
1207                         more = 2; // 3-byte sequences,
1208                                   // 0xd000-0xd7ff, 0xe000-0xffff
1209                         break;
1210                 case 0xf0:
1211                         // don't allow overlong sequences for 0-0xffff
1212                         if ((p[i] & 0xff) < 0x90)
1213                                 break;
1214                 case 0xf1:      // 0x40000-0x7ffff
1215                 case 0xf2:      // 0x80000-0xbffff
1216                 case 0xf3:      // 0xc0000-0xfffff
1217                         more = 3; // 4-byte sequences, 0x10000-0xfffff
1218                         break;
1219                 case 0xf4:
1220                         // don't allow more than 0x10ffff
1221                         if ((p[i] & 0xff) >= 0x90)
1222                                 break;
1223                         more = 3; // 4-byte sequence, 0x100000-0x10ffff
1224                         break;
1225                 }
1226                 if (more) {
1227                         // check that all continuation bytes are valid
1228                         do {
1229                                 if ((p[i++] & 0xc0) != 0x80)
1230                                         break;
1231                         } while (--more);
1232                         if (!more)
1233                                 continue;
1234                 }
1235                 Input h = here_input ();
1236                 h.set (h.get_source_file (), h.start () + oldi, h.start () + i);
1237                 h.warning (_ ("non-UTF-8 input").c_str ());
1238         }
1239         return p;
1240 }
1241
1242
1243 /*
1244  urg, belong to string (_convert)
1245  and should be generalised
1246  */
1247 void
1248 strip_leading_white (string&s)
1249 {
1250         ssize i = 0;
1251         for (;  i < s.length (); i++)
1252                 if (!isspace (s[i]))
1253                         break;
1254
1255         s = s.substr (i);
1256 }
1257
1258 void
1259 strip_trailing_white (string&s)
1260 {
1261         ssize i = s.length ();
1262         while (i--)
1263                 if (!isspace (s[i]))
1264                         break;
1265
1266         s = s.substr (0, i + 1);
1267 }
1268
1269
1270
1271 Lilypond_version oldest_version ("2.7.38");
1272
1273
1274 bool
1275 is_valid_version (string s)
1276 {
1277   Lilypond_version current ( MAJOR_VERSION "." MINOR_VERSION "." PATCH_LEVEL );
1278   Lilypond_version ver (s);
1279   if (!ver)
1280   {
1281           non_fatal_error (_f ("Invalid version string \"%s\"", s));
1282           return false;
1283   }
1284   if (ver < oldest_version)
1285         {
1286                 non_fatal_error (_f ("file too old: %s (oldest supported: %s)", ver.to_string (), oldest_version.to_string ()));
1287                 non_fatal_error (_ ("consider updating the input with the convert-ly script"));
1288                 return false;
1289         }
1290
1291   if (ver > current)
1292         {
1293                 non_fatal_error (_f ("program too old: %s (file requires: %s)",  current.to_string (), ver.to_string ()));
1294                 return false;
1295         }
1296   return true;
1297 }
1298
1299
1300 /*
1301   substitute _
1302 */
1303 string
1304 lyric_fudge (string s)
1305 {
1306         size_t i=0;
1307
1308         while ((i = s.find ('_', i)) != string::npos)
1309         {
1310                 s[i++] = ' ';
1311         }
1312         return s;
1313 }
1314
1315 /*
1316 Convert "NUM/DEN" into a '(NUM . DEN) cons.
1317 */
1318 SCM
1319 scan_fraction (string frac)
1320 {
1321         ssize i = frac.find ('/');
1322         string left = frac.substr (0, i);
1323         string right = frac.substr (i + 1, (frac.length () - i + 1));
1324
1325         return scm_cons (scm_c_read_string (left.c_str ()),
1326                          scm_c_read_string (right.c_str ()));
1327 }
1328
1329 SCM
1330 lookup_markup_command (string s)
1331 {
1332         return Lily::lookup_markup_command (ly_string2scm (s));
1333 }
1334
1335 SCM
1336 lookup_markup_list_command (string s)
1337 {
1338         return Lily::lookup_markup_list_command (ly_string2scm (s));
1339 }
1340
1341 /* Shut up lexer warnings.  */
1342 #if YY_STACK_USED
1343
1344 static void
1345 yy_push_state (int)
1346 {
1347 }
1348
1349 static void
1350 yy_pop_state ()
1351 {
1352 }
1353
1354 static int
1355 yy_top_state ()
1356 {
1357   return 0;
1358 }
1359
1360 static void
1361 silence_lexer_warnings ()
1362 {
1363    (void) yy_start_stack_ptr;
1364    (void) yy_start_stack_depth;
1365    (void) yy_start_stack;
1366    (void) yy_push_state;
1367    (void) yy_pop_state;
1368    (void) yy_top_state;
1369    (void) silence_lexer_warnings;
1370 }
1371 #endif