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