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