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