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