]> git.donarmstrong.com Git - lilypond.git/blob - lily/lexer.ll
release: 0.1.61
[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 "identifier.hh"
37 void strip_trailing_white (String&);
38 void strip_leading_white (String&);
39
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]
82 HORIZONTALWHITE         [ \t]
83 BLACK           [^ \n\t\f]
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");
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.length_i ()-1);
142         DOUT << "#include `" << s << "\'\n";
143         new_input (s,source_global_l);
144         yy_pop_state ();
145 }
146 <incl>\"[^"]*   { // backup rule
147         cerr << "missing end quote" << endl;
148         exit (1);
149 }
150 <notes>{RESTNAME}       {
151         const char *s = YYText ();
152         yylval.string = new String (s); 
153         DOUT << "rest:"<< yylval.string;
154         return RESTNAME;
155 }
156 <INITIAL,lyrics,notes>\\\${BLACK}*{WHITE}       {
157         String s=YYText () + 2;
158         s=s.left_str (s.length_i () - 1);
159         return scan_escaped_word (s);
160 }
161 <INITIAL,lyrics,notes>\${BLACK}*{WHITE}         {
162         String s=YYText () + 1;
163         s=s.left_str (s.length_i () - 1);
164         return scan_bare_word (s);
165 }
166 <INITIAL,lyrics,notes>\\\${BLACK}*              { // backup rule
167         cerr << "white expected" << endl;
168         exit (1);
169 }
170 <INITIAL,lyrics,notes>\${BLACK}*                { // backup rule
171         cerr << "white expected" << endl;
172         exit (1);
173 }
174 <notes>{
175         {ALPHAWORD}/\'  {
176                 post_quotes_b_ = true;
177                 return scan_bare_word (YYText ());
178         }
179         \'+             {
180                 yylval.i = YYLeng ();
181                 if (post_quotes_b_) {
182                         post_quotes_b_ = false;
183                         return POST_QUOTES;
184                 } else
185                         return PRE_QUOTES;
186         }
187         {ALPHAWORD}     {
188                 return scan_bare_word (YYText ());
189
190         }
191
192         {NOTECOMMAND}   {
193                 return scan_escaped_word (YYText ()+1);
194         }
195
196         {DIGIT}         {
197                 yylval.i = String_convert::dec2_i (String (YYText ()));
198                 return DIGIT;
199         }
200
201         {UNSIGNED}              {
202                 yylval.i = String_convert::dec2_i (String (YYText ()));
203                 return UNSIGNED;
204         }
205
206         \" {
207                 start_quote ();
208         }
209 }
210
211 \"              {
212         start_quote ();
213 }
214 <quote>{
215         \\{ESCAPED}     {
216                 *yylval.string += escaped_char(YYText()[1]);
217         }
218         [^\\"]+ {
219                 *yylval.string += YYText ();
220         }
221         \"      {
222                 DOUT << "quoted string: `" << *yylval.string << "'\n";
223                 yy_pop_state ();
224                 return STRING;
225         }
226         .       {
227                 *yylval.string += YYText ();
228         }
229 }
230
231 <lyrics>{
232
233         \" {
234                 start_quote ();
235         }
236         {UNSIGNED}              {
237                 yylval.i = String_convert::dec2_i (String (YYText ()));
238                 return UNSIGNED;
239         }
240         {NOTECOMMAND}   {
241                 return scan_escaped_word (YYText ()+1);
242         }
243         {LYRICS} {
244                 /* ugr. This sux. */
245                 String s (YYText ()); 
246                 int i = 0;
247                 while ((i=s.index_i ("_")) != -1) // change word binding "_" to " "
248                         *(s.ch_l () + i) = ' ';
249                 if ((i=s.index_i ("\\,")) != -1)   // change "\," to TeX's "\c "
250                         {
251                         *(s.ch_l () + i + 1) = 'c';
252                         s = s.left_str (i+2) + " " + s.right_str (s.length_i ()-i-2);
253                         }
254                 yylval.string = new String (s);
255                 DOUT << "lyric : `" << s << "'\n";
256                 return STRING;
257         }
258         . {
259                 return yylval.c = YYText ()[0];
260         }
261 }
262
263 <<EOF>> {
264         DOUT << "<<eof>>";
265
266         if (! close_input ()) { 
267           yyterminate (); // can't move this, since it actually rets a YY_NULL
268         }
269 }
270 {WORD}  {
271         return scan_bare_word (YYText ());
272 }
273 {KEYWORD}       {
274         return scan_escaped_word (YYText ()+1);
275 }
276 {REAL}          {
277         Real r;
278         int cnv=sscanf (YYText (), "%lf", &r);
279         assert (cnv == 1);
280         DOUT  << "REAL" << r<<'\n';
281         yylval.real = r;
282         return REAL;
283 }
284
285 {UNSIGNED}      {
286         yylval.i = String_convert::dec2_i (String (YYText ()));
287         return UNSIGNED;
288 }
289
290 [{}]    {
291
292         DOUT << "parens\n";
293         return YYText ()[0];
294 }
295 [*:=]           {
296         char c = YYText ()[0];
297         DOUT << "misc char" <<c<<"\n";
298         return c;
299 }
300
301 <lyrics,notes>{PLET}    {
302         return yylval.i = PLET;
303 }
304
305 <lyrics,notes>{TELP}    {
306         return yylval.i = TELP;
307 }
308
309 <INITIAL,notes>.        {
310         return yylval.c = YYText ()[0];
311 }
312
313 <INITIAL,lyrics,notes>\\. {
314     char c= YYText ()[1];
315     yylval.c = c;
316     switch (c) {
317     case '>':
318         return E_BIGGER;
319     case '<':
320         return E_SMALLER;
321     case '!':
322         return E_EXCLAMATION;
323     default:
324         return E_CHAR;
325     }
326 }
327
328 <*>.            {
329         String msg= String ("illegal character: ") +String (YYText ()[0]);
330         LexerError (msg.ch_C ());
331         return YYText ()[0];
332 }
333
334 %%
335
336 void
337 My_lily_lexer::push_note_state ()
338 {
339         yy_push_state (notes);
340 }
341
342 void
343 My_lily_lexer::push_lyric_state ()
344 {
345         yy_push_state (lyrics);
346 }
347 void
348 My_lily_lexer::pop_state ()
349 {
350         yy_pop_state ();
351 }
352
353 int
354 My_lily_lexer::scan_escaped_word (String str)
355 {       
356         DOUT << "\\word: `" << str<<"'\n";
357         int l = lookup_keyword (str);
358         if (l != -1) {
359                 DOUT << "(keyword)\n";
360                 return l;
361         }
362         Identifier * id = lookup_identifier (str);
363         if (id) {
364                 DOUT << "(identifier)\n";
365                 yylval.id = id;
366                 return id->token_code_i_;
367         }
368         if (YYSTATE != notes) {
369                 Melodic_req * mel_l = lookup_melodic_req_l (str);
370                 if (mel_l) {
371                     DOUT << "(notename)\n";
372                     yylval.melreq = mel_l;
373                     return NOTENAME_ID;
374                 }
375         }
376         String msg ("Unknown escaped string: `" + str + "'");   
377         LexerError (msg.ch_C ());
378         DOUT << "(string)";
379         String *sp = new String (str);
380         yylval.string=sp;
381         return STRING;
382 }
383
384 int
385 My_lily_lexer::scan_bare_word (String str)
386 {
387         DOUT << "word: `" << str<< "'\n";       
388         if (YYSTATE == notes){
389                 Melodic_req * mel_l = lookup_melodic_req_l (str);
390                 if (mel_l) {
391                     DOUT << "(notename)\n";
392                     yylval.melreq = mel_l;
393                     return NOTENAME_ID;
394                 }
395         }
396
397         yylval.string=new String (str);
398         return STRING;
399 }
400
401 bool
402 My_lily_lexer::note_state_b () const
403 {
404         return YY_START == notes;
405 }
406
407 bool
408 My_lily_lexer::lyric_state_b () const
409 {
410         return YY_START == lyrics;
411 }
412
413 void
414 strip_trailing_white (String&s)
415 {
416         int i=0;
417         for (;  i < s.length_i (); i++) 
418                 if (!isspace (s[i]))
419                         break;
420
421         s = s.nomid_str (0, i);
422 }
423
424 void
425 strip_leading_white (String&s)
426 {
427         int i=s.length_i ();    
428         while (i--) 
429                 if (!isspace (s[i]))
430                         break;
431
432         s = s.left_str (i+1);
433 }