]> git.donarmstrong.com Git - lilypond.git/blob - lily/lexer.ll
patch::: 1.1.10.jcn1: koorden
[lilypond.git] / lily / lexer.ll
1 %{ // -*-Fundamental-*-
2 /*
3   lexer.l -- implement the Flex lexer
4
5   source file of the LilyPond music typesetter
6
7   (c) 1996,1997 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 */
9
10
11 /*
12   backup rules
13
14   after making a change to the lexer rules, run 
15       flex -b <this lexer file>
16   and make sure that 
17       lex.backup
18   contains no backup states, but only the reminder
19       Compressed tables always back up.
20   (don-t forget to rm lex.yy.cc :-)
21  */
22
23
24 #include <stdio.h>
25 #include <ctype.h>
26
27 #include "string.hh"
28 #include "string-convert.hh"
29 #include "my-lily-lexer.hh"
30 #include "array.hh"
31 #include "interval.hh"
32 #include "parser.hh"
33 #include "debug.hh"
34 #include "parseconstruct.hh"
35 #include "main.hh"
36 #include "musical-request.hh"
37 #include "identifier.hh"
38 void strip_trailing_white (String&);
39 void strip_leading_white (String&);
40
41 #define start_quote()   \
42         yy_push_state (quote);\
43         yylval.string = new String
44
45 #define yylval (*(YYSTYPE*)lexval_l)
46
47 #define YY_USER_ACTION  add_lexed_char (YYLeng ());
48 /*
49
50 LYRICS          ({AA}|{TEX})[^0-9 \t\n\f]*
51
52 */
53
54 %}
55
56 %option c++
57 %option noyywrap
58 %option nodefault
59 %option debug
60 %option yyclass="My_lily_lexer"
61 %option stack
62 %option never-interactive 
63 %option warn
64
65 %x chords
66 %x incl
67 %x lyrics
68 %x notes
69 %x quote
70 %x longcomment
71
72
73 A               [a-zA-Z]
74 AA              {A}|_
75 N               [0-9]
76 AN              {AA}|{N}
77 PUNCT           [?!:']
78 ACCENT          \\[`'"^]
79 NATIONAL  [\001-\006\021-\027\031\036\200-\377]
80 TEX             {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}
81 WORD            {A}{AN}*
82 ALPHAWORD       {A}+
83 DIGIT           {N}
84 UNSIGNED        {N}+
85 INT             -?{UNSIGNED}
86 REAL            ({INT}\.{N}*)|(-?\.{N}+)
87 KEYWORD         \\{WORD}
88 WHITE           [ \n\t\f\r]
89 HORIZONTALWHITE         [ \t]
90 BLACK           [^ \n\t\f\r]
91 RESTNAME        [rs]
92 NOTECOMMAND     \\{A}+
93 LYRICS          ({AA}|{TEX})[^0-9 \t\n\f]*
94 ESCAPED         [nt\\'"]
95 PLET            \\\[
96 TELP            \\\]
97 EXTENDER        [_][_]
98
99 %%
100
101
102 <*>\r           {
103         // windows-suck-suck-suck
104 }
105
106 <INITIAL,chords,incl,lyrics,notes>{
107   "%{"  {
108         yy_push_state (longcomment);
109   }
110   %[^{\n].*\n   {
111   }
112   %[^{\n]       { // backup rule
113   }
114   %\n   {
115   }
116   %[^{\n].*     {
117   }
118   {WHITE}+      {
119
120   }
121 }
122
123 <longcomment>{
124         [^\%]*          {
125         }
126         \%*[^}%]*               {
127
128         }
129         "%"+"}"         {
130                 yy_pop_state ();
131         }
132         <<EOF>>         {
133                 LexerError (_ ("EOF found inside a comment").ch_C ());
134                 if (! close_input ()) 
135                   yyterminate (); // can't move this, since it actually rets a YY_NULL
136         }
137 }
138
139
140 <INITIAL,chords,lyrics,notes>\\maininput           {
141         start_main_input ();
142 }
143
144 <INITIAL,chords,lyrics,notes>\\include           {
145         yy_push_state (incl);
146 }
147 <incl>\"[^"]*\";?   { /* got the include file name */
148         String s (YYText ()+1);
149         s = s.left_str (s.index_last_i ('"'));
150         DOUT << "#include `" << s << "\'\n";
151         new_input (s,source_global_l);
152         yy_pop_state ();
153 }
154 <incl>\\{BLACK}*;?{WHITE} { /* got the include identifier */
155         String s = YYText () + 1;
156         strip_trailing_white (s);
157         if (s.length_i () && (s[s.length_i () - 1] == ';'))
158           s = s.left_str (s.length_i () - 1);
159         DOUT << "#include `\\" << s << "'\n";
160         Identifier * id = lookup_identifier (s);
161         if (id) 
162           {
163             String* s_l = id->access_content_String (false);
164             DOUT << "#include `" << *s_l << "\'\n";
165             new_input (*s_l, source_global_l);
166
167             yy_pop_state ();
168           }
169         else
170           {
171             String msg (_f ("undefined identifier: `%s\'", s ));        
172             LexerError (msg.ch_C ());
173           }
174 }
175 <incl>\"[^"]*   { // backup rule
176         cerr << _ ("missing end quote") << endl;
177         exit (1);
178 }
179 <notes>{RESTNAME}       {
180         const char *s = YYText ();
181         yylval.string = new String (s); 
182         DOUT << "rest:"<< yylval.string;
183         return RESTNAME;
184 }
185 <notes>R                {
186         return MEASURES;
187 }
188 <INITIAL,chords,lyrics,notes>\\\${BLACK}*{WHITE}        {
189         String s=YYText () + 2;
190         s=s.left_str (s.length_i () - 1);
191         return scan_escaped_word (s); 
192 }
193 <INITIAL,chords,lyrics,notes>\${BLACK}*{WHITE}          {
194         String s=YYText () + 1;
195         s=s.left_str (s.length_i () - 1);
196         return scan_bare_word (s);
197 }
198 <INITIAL,chords,lyrics,notes>\\\${BLACK}*               { // backup rule
199         cerr << _ ("white expected") << endl;
200         exit (1);
201 }
202 <INITIAL,chords,lyrics,notes>\${BLACK}*         { // backup rule
203         cerr << _ ("white expected") << endl;
204         exit (1);
205 }
206 <notes>{
207         {ALPHAWORD}     {
208                 return scan_bare_word (YYText ());
209         }
210
211         {NOTECOMMAND}   {
212                 return scan_escaped_word (YYText () + 1); 
213         }
214
215         {DIGIT}         {
216                 yylval.i = String_convert::dec2_i (String (YYText ()));
217                 return DIGIT;
218         }
219
220         {UNSIGNED}              {
221                 yylval.i = String_convert::dec2_i (String (YYText ()));
222                 return UNSIGNED;
223         }
224
225         \" {
226                 start_quote ();
227         }
228 }
229
230 \"              {
231         start_quote ();
232 }
233 <quote>{
234         \\{ESCAPED}     {
235                 *yylval.string += to_str (escaped_char(YYText()[1]));
236         }
237         [^\\"]+ {
238                 *yylval.string += YYText ();
239         }
240         \"      {
241                 DOUT << "quoted string: `" << *yylval.string << "'\n";
242                 yy_pop_state ();
243                 return STRING;
244         }
245         .       {
246                 *yylval.string += YYText ();
247         }
248 }
249
250 <lyrics>{
251         \" {
252                 start_quote ();
253         }
254         {UNSIGNED}              {
255                 yylval.i = String_convert::dec2_i (String (YYText ()));
256                 return UNSIGNED;
257         }
258         {NOTECOMMAND}   {
259                 return scan_escaped_word (YYText () + 1);
260         }
261         {LYRICS} {
262                 /* ugr. This sux. */
263                 String s (YYText ()); 
264                 if (s == "__")
265                         return yylval.i = EXTENDER;
266                 int i = 0;
267                 while ((i=s.index_i ("_")) != -1) // change word binding "_" to " "
268                         *(s.ch_l () + i) = ' ';
269                 if ((i=s.index_i ("\\,")) != -1)   // change "\," to TeX's "\c "
270                         {
271                         *(s.ch_l () + i + 1) = 'c';
272                         s = s.left_str (i+2) + " " + s.right_str (s.length_i ()-i-2);
273                         }
274                 yylval.string = new String (s);
275                 DOUT << "lyric : `" << s << "'\n";
276                 return STRING;
277         }
278         . {
279                 return yylval.c = YYText ()[0];
280         }
281 }
282 <chords>{
283         {ALPHAWORD}     {
284                 return scan_bare_word (YYText ());
285         }
286         {UNSIGNED}              {
287                 yylval.i = String_convert::dec2_i (String (YYText ()));
288                 return UNSIGNED;
289         }
290         . {
291                 return yylval.c = YYText ()[0];
292         }
293 }
294
295 <<EOF>> {
296         DOUT << "<<eof>>";
297
298         if (! close_input ()) { 
299           yyterminate (); // can't move this, since it actually rets a YY_NULL
300         }
301 }
302
303
304 {WORD}  {
305         return scan_bare_word (YYText ());
306 }
307 {KEYWORD}       {
308         return scan_escaped_word (YYText () + 1);
309 }
310 {REAL}          {
311         Real r;
312         int cnv=sscanf (YYText (), "%lf", &r);
313         assert (cnv == 1);
314         DOUT  << "REAL" << r<<'\n';
315         yylval.real = r;
316         return REAL;
317 }
318
319 {UNSIGNED}      {
320         yylval.i = String_convert::dec2_i (String (YYText ()));
321         return UNSIGNED;
322 }
323
324 [{}]    {
325
326         DOUT << "parens\n";
327         return YYText ()[0];
328 }
329 [*:=]           {
330         char c = YYText ()[0];
331         DOUT << "misc char" <<c<<"\n";
332         return c;
333 }
334
335 <lyrics,notes>{PLET}    {
336         return yylval.i = PLET;
337 }
338
339 <lyrics,notes>{TELP}    {
340         return yylval.i = TELP;
341 }
342
343 <INITIAL,notes>.        {
344         return yylval.c = YYText ()[0];
345 }
346
347 <INITIAL,lyrics,notes>\\. {
348     char c= YYText ()[1];
349     yylval.c = c;
350     switch (c) {
351     case '>':
352         return E_BIGGER;
353     case '<':
354         return E_SMALLER;
355     case '!':
356         return E_EXCLAMATION;
357     default:
358         return E_CHAR;
359     }
360 }
361
362 <*>.            {
363         String msg = _f ("illegal character: `%c\'", YYText ()[0]);
364         LexerError (msg.ch_C ());
365         return YYText ()[0];
366 }
367
368 %%
369
370 void
371 My_lily_lexer::push_note_state ()
372 {
373         yy_push_state (notes);
374 }
375
376 void
377 My_lily_lexer::push_chord_state ()
378 {
379         yy_push_state (chords);
380 }
381
382 void
383 My_lily_lexer::push_lyric_state ()
384 {
385         yy_push_state (lyrics);
386 }
387
388 void
389 My_lily_lexer::pop_state ()
390 {
391         yy_pop_state ();
392 }
393
394 int
395 My_lily_lexer::scan_escaped_word (String str)
396 {       
397         DOUT << "\\word: `" << str<<"'\n";
398         int l = lookup_keyword (str);
399         if (l != -1) {
400                 DOUT << "(keyword)\n";
401                 return l;
402         }
403         Identifier * id = lookup_identifier (str);
404         if (id) {
405                 DOUT << "(identifier)\n";
406                 yylval.id = id;
407                 return id->token_code_i_;
408         }
409         if ((YYSTATE != notes) && (YYSTATE != chords)) {
410                 if (notename_b (str))
411                         {
412                         yylval.pitch = new Musical_pitch (lookup_pitch (str));
413                         yylval.pitch->set_spot (Input (source_file_l (), 
414                           here_ch_C ()));
415                         return NOTENAME_PITCH;
416                         }
417         }
418         if (check_debug)
419                 print_declarations (true);
420         String msg (_f ("unknown escaped string: `\\%s\'", str));       
421         LexerError (msg.ch_C ());
422         DOUT << "(string)";
423         String *sp = new String (str);
424         yylval.string=sp;
425         return STRING;
426 }
427
428 int
429 My_lily_lexer::scan_bare_word (String str)
430 {
431         DOUT << "word: `" << str<< "'\n";       
432         if ((YYSTATE == notes) || (YYSTATE == chords)) {
433                 if (notename_b (str)) {
434                     DOUT << "(notename)\n";
435                     yylval.pitch = new Musical_pitch (lookup_pitch (str));
436                     yylval.pitch->set_spot (Input (source_file_l (), 
437                       here_ch_C ()));
438                     return NOTENAME_PITCH;
439                 }
440         }
441
442         yylval.string=new String (str);
443         return STRING;
444 }
445
446 bool
447 My_lily_lexer::note_state_b () const
448 {
449         return YY_START == notes;
450 }
451
452 bool
453 My_lily_lexer::chord_state_b () const
454 {
455         return YY_START == chords;
456 }
457
458 bool
459 My_lily_lexer::lyric_state_b () const
460 {
461         return YY_START == lyrics;
462 }
463
464 /*
465  urg, belong to String(_convert)
466  and should be generalised 
467  */
468 void
469 strip_leading_white (String&s)
470 {
471         int i=0;
472         for (;  i < s.length_i (); i++) 
473                 if (!isspace (s[i]))
474                         break;
475
476         s = s.nomid_str (0, i);
477 }
478
479 void
480 strip_trailing_white (String&s)
481 {
482         int i=s.length_i ();    
483         while (i--) 
484                 if (!isspace (s[i]))
485                         break;
486
487         s = s.left_str (i+1);
488 }
489