]> git.donarmstrong.com Git - lilypond.git/blob - lily/lexer.ll
release: 1.1.1
[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 incl
66 %x lyrics
67 %x notes
68 %x quote
69 %x longcomment
70
71
72 A               [a-zA-Z]
73 AA              {A}|_
74 N               [0-9]
75 AN              {AA}|{N}
76 PUNCT           [?!:']
77 ACCENT          \\[`'"^]
78 NATIONAL  [\001-\006\021-\027\031\036\200-\377]
79 TEX             {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}
80 WORD            {A}{AN}*
81 ALPHAWORD       {A}+
82 DIGIT           {N}
83 UNSIGNED        {N}+
84 INT             -?{UNSIGNED}
85 REAL            ({INT}\.{N}*)|(-?\.{N}+)
86 KEYWORD         \\{WORD}
87 WHITE           [ \n\t\f\r]
88 HORIZONTALWHITE         [ \t]
89 BLACK           [^ \n\t\f\r]
90 RESTNAME        [rs]
91 NOTECOMMAND     \\{A}+
92 LYRICS          ({AA}|{TEX})[^0-9 \t\n\f]*
93 ESCAPED         [nt\\'"]
94 PLET            \\\[
95 TELP            \\\]
96
97 %%
98
99
100 <*>\r           {
101         // windows-suck-suck-suck
102 }
103
104 <notes,incl,INITIAL,lyrics>{
105   "%{"  {
106         yy_push_state (longcomment);
107   }
108   %[^{\n].*\n   {
109   }
110   %[^{\n]       { // backup rule
111   }
112   %\n   {
113   }
114   %[^{\n].*     {
115   }
116   {WHITE}+      {
117
118   }
119 }
120
121 <longcomment>{
122         [^\%]*          {
123         }
124         \%*[^}%]*               {
125
126         }
127         "%"+"}"         {
128                 yy_pop_state ();
129         }
130         <<EOF>>         {
131                 LexerError (_ ("EOF found inside a comment").ch_C ());
132                 if (! close_input ()) 
133                   yyterminate (); // can't move this, since it actually rets a YY_NULL
134         }
135 }
136
137
138 <notes,INITIAL,lyrics>\\maininput           {
139         start_main_input ();
140 }
141
142 <notes,INITIAL,lyrics>\\include           {
143         yy_push_state (incl);
144 }
145 <incl>\"[^"]*\";?   { /* got the include file name */
146         String s (YYText ()+1);
147         s = s.left_str (s.index_last_i ('"'));
148         DOUT << "#include `" << s << "\'\n";
149         new_input (s,source_global_l);
150         yy_pop_state ();
151 }
152 <incl>\\{BLACK}*;?{WHITE} { /* got the include identifier */
153         String s = YYText () + 1;
154         strip_trailing_white (s);
155         if (s.length_i () && (s[s.length_i () - 1] == ';'))
156           s = s.left_str (s.length_i () - 1);
157         DOUT << "#include `\\" << s << "'\n";
158         Identifier * id = lookup_identifier (s);
159         if (id) 
160           {
161             String* s_l = id->access_content_String (false);
162             DOUT << "#include `" << *s_l << "\'\n";
163             new_input (*s_l, source_global_l);
164
165             yy_pop_state ();
166           }
167         else
168           {
169             String msg (_f ("undefined identifier: `%s\'", s ));        
170             LexerError (msg.ch_C ());
171           }
172 }
173 <incl>\"[^"]*   { // backup rule
174         cerr << _ ("missing end quote") << endl;
175         exit (1);
176 }
177 <notes>{RESTNAME}       {
178         const char *s = YYText ();
179         yylval.string = new String (s); 
180         DOUT << "rest:"<< yylval.string;
181         return RESTNAME;
182 }
183 <notes>R                {
184         return MEASURES;
185 }
186 <INITIAL,lyrics,notes>\\\${BLACK}*{WHITE}       {
187         String s=YYText () + 2;
188         s=s.left_str (s.length_i () - 1);
189         return scan_escaped_word (s); 
190 }
191 <INITIAL,lyrics,notes>\${BLACK}*{WHITE}         {
192         String s=YYText () + 1;
193         s=s.left_str (s.length_i () - 1);
194         return scan_bare_word (s);
195 }
196 <INITIAL,lyrics,notes>\\\${BLACK}*              { // backup rule
197         cerr << _ ("white expected") << endl;
198         exit (1);
199 }
200 <INITIAL,lyrics,notes>\${BLACK}*                { // backup rule
201         cerr << _ ("white expected") << endl;
202         exit (1);
203 }
204 <notes>{
205
206         {ALPHAWORD}     {
207                 return scan_bare_word (YYText ());
208
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         \" {
253                 start_quote ();
254         }
255         {UNSIGNED}              {
256                 yylval.i = String_convert::dec2_i (String (YYText ()));
257                 return UNSIGNED;
258         }
259         {NOTECOMMAND}   {
260                 return scan_escaped_word (YYText () + 1);
261         }
262         {LYRICS} {
263                 /* ugr. This sux. */
264                 String s (YYText ()); 
265                 int i = 0;
266                 while ((i=s.index_i ("_")) != -1) // change word binding "_" to " "
267                         *(s.ch_l () + i) = ' ';
268                 if ((i=s.index_i ("\\,")) != -1)   // change "\," to TeX's "\c "
269                         {
270                         *(s.ch_l () + i + 1) = 'c';
271                         s = s.left_str (i+2) + " " + s.right_str (s.length_i ()-i-2);
272                         }
273                 yylval.string = new String (s);
274                 DOUT << "lyric : `" << s << "'\n";
275                 return STRING;
276         }
277         . {
278                 return yylval.c = YYText ()[0];
279         }
280 }
281
282 <<EOF>> {
283         DOUT << "<<eof>>";
284
285         if (! close_input ()) { 
286           yyterminate (); // can't move this, since it actually rets a YY_NULL
287         }
288 }
289 {WORD}  {
290         return scan_bare_word (YYText ());
291 }
292 {KEYWORD}       {
293         return scan_escaped_word (YYText () + 1);
294 }
295 {REAL}          {
296         Real r;
297         int cnv=sscanf (YYText (), "%lf", &r);
298         assert (cnv == 1);
299         DOUT  << "REAL" << r<<'\n';
300         yylval.real = r;
301         return REAL;
302 }
303
304 {UNSIGNED}      {
305         yylval.i = String_convert::dec2_i (String (YYText ()));
306         return UNSIGNED;
307 }
308
309 [{}]    {
310
311         DOUT << "parens\n";
312         return YYText ()[0];
313 }
314 [*:=]           {
315         char c = YYText ()[0];
316         DOUT << "misc char" <<c<<"\n";
317         return c;
318 }
319
320 <lyrics,notes>{PLET}    {
321         return yylval.i = PLET;
322 }
323
324 <lyrics,notes>{TELP}    {
325         return yylval.i = TELP;
326 }
327
328 <INITIAL,notes>.        {
329         return yylval.c = YYText ()[0];
330 }
331
332 <INITIAL,lyrics,notes>\\. {
333     char c= YYText ()[1];
334     yylval.c = c;
335     switch (c) {
336     case '>':
337         return E_BIGGER;
338     case '<':
339         return E_SMALLER;
340     case '!':
341         return E_EXCLAMATION;
342     default:
343         return E_CHAR;
344     }
345 }
346
347 <*>.            {
348         String msg = _f ("illegal character: `%c\'", YYText ()[0]);
349         LexerError (msg.ch_C ());
350         return YYText ()[0];
351 }
352
353 %%
354
355 void
356 My_lily_lexer::push_note_state ()
357 {
358         yy_push_state (notes);
359 }
360
361 void
362 My_lily_lexer::push_lyric_state ()
363 {
364         yy_push_state (lyrics);
365 }
366 void
367 My_lily_lexer::pop_state ()
368 {
369         yy_pop_state ();
370 }
371
372 int
373 My_lily_lexer::scan_escaped_word (String str)
374 {       
375         DOUT << "\\word: `" << str<<"'\n";
376         int l = lookup_keyword (str);
377         if (l != -1) {
378                 DOUT << "(keyword)\n";
379                 return l;
380         }
381         Identifier * id = lookup_identifier (str);
382         if (id) {
383                 DOUT << "(identifier)\n";
384                 yylval.id = id;
385                 return id->token_code_i_;
386         }
387         if (YYSTATE != notes) {
388                 if (notename_b (str))
389                         {
390                         yylval.pitch = new Musical_pitch (lookup_pitch (str));
391                         yylval.pitch->set_spot (Input (source_file_l (), 
392                           here_ch_C ()));
393                         return NOTENAME_PITCH;
394                         }
395         }
396         if (check_debug)
397                 print_declarations (true);
398         String msg (_f ("unknown escaped string: `\\%s\'", str));       
399         LexerError (msg.ch_C ());
400         DOUT << "(string)";
401         String *sp = new String (str);
402         yylval.string=sp;
403         return STRING;
404 }
405
406 int
407 My_lily_lexer::scan_bare_word (String str)
408 {
409         DOUT << "word: `" << str<< "'\n";       
410         if (YYSTATE == notes){
411                 if (notename_b (str)) {
412                     DOUT << "(notename)\n";
413                     yylval.pitch = new Musical_pitch (lookup_pitch (str));
414                     yylval.pitch->set_spot (Input (source_file_l (), 
415                       here_ch_C ()));
416                     return NOTENAME_PITCH;
417                 }
418         }
419
420         yylval.string=new String (str);
421         return STRING;
422 }
423
424 bool
425 My_lily_lexer::note_state_b () const
426 {
427         return YY_START == notes;
428 }
429
430 bool
431 My_lily_lexer::lyric_state_b () const
432 {
433         return YY_START == lyrics;
434 }
435
436 /*
437  urg, belong to String(_convert)
438  and should be generalised 
439  */
440 void
441 strip_leading_white (String&s)
442 {
443         int i=0;
444         for (;  i < s.length_i (); i++) 
445                 if (!isspace (s[i]))
446                         break;
447
448         s = s.nomid_str (0, i);
449 }
450
451 void
452 strip_trailing_white (String&s)
453 {
454         int i=s.length_i ();    
455         while (i--) 
456                 if (!isspace (s[i]))
457                         break;
458
459         s = s.left_str (i+1);
460 }
461