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