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