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