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