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