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