]> git.donarmstrong.com Git - lilypond.git/blob - lily/my-lily-parser.cc
release: 0.1.63
[lilypond.git] / lily / my-lily-parser.cc
1 /*
2   my-lily-parser.cc -- implement My_lily_parser
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--1998 Han-Wen Nienhuys <hanwen@stack.nl>
7 */
8
9 #include "my-lily-parser.hh"
10 #include "my-lily-lexer.hh"
11 #include "debug.hh"
12 #include "main.hh"
13 #include "music-list.hh"
14 #include "musical-request.hh"
15 #include "command-request.hh"
16 #include "parser.hh"
17 #include "header.hh"
18 #include "file-results.hh"
19 #include "midi-def.hh"
20 #include "paper-def.hh"
21 #include "identifier.hh"
22
23 My_lily_parser::My_lily_parser (Sources * source_l)
24 {
25   first_b_ = true;
26   source_l_ = source_l;
27   lexer_p_ = 0;
28   abbrev_beam_type_i_ = 0;
29   default_duration_.durlog_i_ = 2;
30   default_octave_i_ = 0;
31   textstyle_str_="roman";               // in lexer?
32   error_level_i_ = 0;
33   last_duration_mode_b_ = true;
34   fatal_error_i_ = 0;
35   default_header_p_ =0;
36
37   relative_octave_mode_b_ = false;
38
39   last_melodic_ = new Melodic_req;
40   last_melodic_->octave_i_ = 0; // -1; // huh?
41   last_melodic_->notename_i_ = 0;
42   last_melodic_->accidental_i_ = 0;
43 }
44
45 My_lily_parser::~My_lily_parser()
46 {
47   delete lexer_p_;
48   delete default_header_p_;
49 }
50
51
52 void
53 My_lily_parser::clear_notenames()
54 {
55   lexer_p_->clear_notenames();
56 }
57
58 void
59 My_lily_parser::set_version_check (bool ig)
60 {
61   ignore_version_b_ = ig;
62 }
63
64 void
65 My_lily_parser::parse_file (String init, String s)
66 {
67   lexer_p_ = new My_lily_lexer;
68   init_str_ = init;
69   lexer_p_->main_input_str_ = s;
70
71   *mlog << _("Parsing ... ");
72
73   init_parse_b_ = false;
74   set_yydebug (!monitor->silent_b ("Parser") && check_debug);
75   lexer_p_->new_input (init, source_l_);
76   do_yyparse ();
77
78
79   if (!define_spot_array_.empty())
80     {
81       warning (_("Braces don't match."));
82       error_level_i_ = 1;
83     }
84
85   inclusion_global_array = lexer_p_->filename_str_arr_;
86 }
87
88 void
89 My_lily_parser::remember_spot()
90 {
91   define_spot_array_.push (here_input());
92 }
93
94 char const *
95 My_lily_parser::here_ch_C() const
96 {
97   return lexer_p_->here_ch_C();
98 }
99
100 void
101 My_lily_parser::parser_error (String s)
102 {
103   here_input().error (s);
104   if (fatal_error_i_)
105     exit (fatal_error_i_);
106   error_level_i_ = 1;
107   exit_status_i_ = 1;
108 }
109
110 void
111 My_lily_parser::set_duration_mode (String s)
112 {
113   s = s.upper_str();
114   last_duration_mode_b_ = (s== "LAST");
115 }
116
117 void
118 My_lily_parser::set_octave_mode (String s)
119 {
120   s = s.upper_str();
121   if (s == "RELATIVE")
122     {
123       relative_octave_mode_b_ = true;
124       // must reset these
125       last_melodic_ = new Melodic_req;
126       last_melodic_->octave_i_ = 0; // -1; // huh?
127       last_melodic_->notename_i_ = 0;
128       last_melodic_->accidental_i_ = 0;
129     }
130   else
131     relative_octave_mode_b_ = false;
132 }
133
134 void
135 My_lily_parser::set_abbrev_beam (int type_i)
136 {
137   abbrev_beam_type_i_ = type_i;
138 }
139
140 void
141 My_lily_parser::set_default_duration (Duration const *d)
142 {
143   last_duration_mode_b_ = false;
144   default_duration_ = *d;
145 }
146
147
148 void
149 My_lily_parser::set_last_duration (Duration const *d)
150 {
151   if (last_duration_mode_b_)
152     {
153       default_duration_ = *d;
154       /* 
155         forget plet part,
156         sticky plet factor only within plet brackets
157        */  
158       default_duration_.set_plet (1, 1);
159     }
160 }
161
162 String
163 My_lily_parser::notename_str (Melodic_req* melodic)
164 {
165   // ugh
166   String str ((char)('a' + ((melodic->notename_i_ + 2) % 7)));
167   int i = melodic->accidental_i_;
168   while (i-- > 0) 
169     str += "is";
170   i++;
171   while (i++ < 0)
172     str += "es";
173   return str;
174 }
175
176 Melodic_req* 
177 My_lily_parser::get_melodic_req (Melodic_req* melodic, int quotes)
178 {
179   if (relative_octave_mode_b_)
180     {
181       set_nearest (melodic);
182       int d = melodic->pitch () - last_melodic_->pitch ();
183       int shift = 0;
184       if (quotes && (sign (d) == sign (quotes)))
185         shift -= sign (quotes);
186       if (!quotes && (abs (d) == 6))
187         {
188           String str = _("Octave ambiguity; assuming ");
189           /*
190             [TODO]
191             figure this out.
192
193             If the distance is exactly*) half an octave, there is 
194             no nearest pitch.  In that case, we'll try to guess what 
195             composer/ typist meant.
196             Firstly, we'll do this by comparing the 'notename distance':
197                 
198               f b'   % name-distance: f g a b: 3
199
200             is surely a shorter notename distance than
201
202               f 'b  % name-distance: b c d e f: 4
203
204           (should we give a warning at all, or can we safely assume
205           this is a positive interval up?)
206
207           *) It is conceivable that, musically speaking, the interval
208              with the greater pitch-distance is thought to be smaller?
209
210           */
211
212           int name_delta = melodic->notename_i_ - last_melodic_->notename_i_;
213           int name_near = abs (name_delta) % 7;
214           int name_wrap = (7 - abs (name_delta)) % 7;
215           if (name_near != name_wrap)
216             shift = name_near < name_wrap ? sign (name_delta) : -sign (name_delta);
217           else if (sign (last_melodic_->accidental_i_) 
218             != sign (melodic->accidental_i_))
219             shift = last_melodic_->accidental_i_ - melodic->accidental_i_;
220           else
221             shift = -1;
222           String name_str = notename_str (melodic);
223           str += shift > 0 ? name_str + "'" : "'" + name_str;
224           if (sign (d) == sign (shift))
225             shift = 0;
226           melodic->warning (str);
227         }
228       melodic->octave_i_ += quotes + shift;
229     }
230   else
231     {
232       Melodic_req nearest (*melodic);
233       set_nearest (&nearest);
234       melodic->octave_i_ += quotes;
235
236       if (find_quarts_global_b)
237         {
238           int e = melodic->pitch () - nearest.pitch ();
239           if (e)
240             {
241               int d = melodic->pitch () - last_melodic_->pitch ();
242               String str = _("Interval greater than quart");
243               int n = 1 + (abs (d) - 1) / 12;
244               String quote_str ('\'', n);
245               str += _(", relative: ");
246               String name_str = notename_str (melodic);
247               str += d < 0 ? quote_str + name_str : name_str + quote_str;
248               melodic->warning (str);
249             }
250         }
251     }
252   delete last_melodic_;
253   last_melodic_ = melodic->clone ()->musical ()->melodic ();
254   return melodic;
255 }
256
257 void
258 My_lily_parser::set_nearest (Melodic_req* melodic)
259 {
260   melodic->octave_i_ = last_melodic_->octave_i_;
261   int d = melodic->pitch () - last_melodic_->pitch ();
262   if (abs (d) > 6)
263     melodic->octave_i_ -= sign (d);
264 }
265
266 Chord*
267 My_lily_parser::get_word_element (Text_def* tdef_p, Duration * duration_p)
268 {
269   Chord* velt_p = new Request_chord;
270
271   Lyric_req* lreq_p = new Lyric_req (tdef_p);
272
273   lreq_p->duration_ = *duration_p;
274   lreq_p->set_spot (here_input());
275
276   velt_p->add (lreq_p);
277
278   delete  duration_p;
279   return velt_p;
280 }
281
282
283 Chord *
284 My_lily_parser::get_rest_element (String s,  Duration * duration_p)
285 {
286   Chord* velt_p = new Request_chord;
287   velt_p->set_spot (here_input());
288
289   if (s=="s")
290     { /* Space */
291       Skip_req * skip_p = new Skip_req;
292       skip_p->duration_ = *duration_p;
293
294       skip_p->set_spot (here_input());
295       velt_p->add (skip_p);
296     }
297   else
298     {
299       Rest_req * rest_req_p = new Rest_req;
300       rest_req_p->duration_ = *duration_p;
301       rest_req_p->set_spot (here_input());
302
303       velt_p->add (rest_req_p);
304     }
305
306   delete duration_p;
307   return velt_p;
308 }
309
310 Chord *
311 My_lily_parser::get_note_element (Note_req *rq, Duration * duration_p)
312 {
313   Chord*v = new Request_chord;
314   v->set_spot (here_input ());
315
316   v->add (rq);
317
318   // too bad parser reads (default) duration via member access,
319   // this hack will do for now..
320   if (abbrev_beam_type_i_)
321     {
322       assert (!duration_p->plet_b ());
323       duration_p->set_plet (1, 2);
324     }
325   rq->set_duration (*duration_p);
326   rq->set_spot (here_input ());
327   delete duration_p ;
328   return v;
329 }
330
331 Array<Request*>*
332 My_lily_parser::get_parens_request (int t)
333 {
334   Array<Request*>& reqs = *new Array<Request*>;
335   switch (t)
336     {
337     case '~':
338       reqs.push (new Tie_req);
339       break;
340     case BEAMPLET:
341     case MAEBTELP:
342       {
343         Plet_req* p = new Plet_req;
344         p->plet_i_ = plet_.type_i_;
345         reqs.push (p);
346       }
347       /* fall through */
348     case '[':
349     case ']':
350       {
351         if (!abbrev_beam_type_i_)
352           {
353             reqs.push (new Beam_req);
354           }
355         else
356           {
357             Abbreviation_beam_req* a = new Abbreviation_beam_req;
358             a->type_i_ = abbrev_beam_type_i_;
359             if (t==']')
360               abbrev_beam_type_i_ = 0;
361             reqs.push (a);
362           }
363       }
364       break;
365
366     case '>':
367     case '!':
368     case '<':
369       reqs.push (new Span_dynamic_req);
370       break;
371
372     case PLET:  
373     case TELP:
374       {
375         Plet_req* p = new Plet_req;
376         p->plet_i_ = plet_.type_i_;
377         reqs.push (p);
378       }
379       break;
380     case ')':
381     case '(':
382       {
383         reqs.push (new Slur_req);
384       }
385       break;
386     default:
387       assert (false);
388       break;
389     }
390
391   switch (t)
392     {
393     case BEAMPLET:
394       reqs.top ()->span()->spantype = Span_req::START;
395       /* fall through */
396     case '<':
397     case '>':
398     case '(':
399     case '[':
400     case PLET:
401       reqs[0]->span ()->spantype = Span_req::START;
402       break;
403     case MAEBTELP:
404       reqs.top ()->span()->spantype = Span_req::STOP;
405       /* fall through */
406     case '!':
407     case ')':
408     case ']':
409       reqs[0]->span ()->spantype = Span_req::STOP;
410       break;
411
412     default:
413       break;
414     }
415
416   for (int i = 0; i < reqs.size (); i++)
417     if (reqs[i]->musical ()->span_dynamic ())
418       {
419         Span_dynamic_req* s_l= (reqs[i]->musical ()->span_dynamic ()) ;
420         s_l->dynamic_dir_ = (t == '<') ? UP:DOWN;
421       }
422
423   // ugh? don't we do this in the parser too?
424   reqs[0]->set_spot (here_input());
425   return &reqs;
426 }
427
428 void
429 My_lily_parser::add_requests (Chord*v)
430 {
431   for (int i = 0; i < pre_reqs.size(); i++)
432     {
433       v->add (pre_reqs[i]);
434     }
435   pre_reqs.clear();
436   for (int i = 0; i <post_reqs.size(); i++)
437     {
438       v->add (post_reqs[i]);
439     }
440   post_reqs.clear();
441 }
442
443 Input
444 My_lily_parser::pop_spot()
445 {
446   return define_spot_array_.pop();
447 }
448
449 Input
450 My_lily_parser::here_input() const
451 {
452   Source_file * f_l= lexer_p_->source_file_l();
453   return Input (f_l, here_ch_C());
454 }
455
456 void
457 My_lily_parser::add_notename (String s, Melodic_req * m_p)
458 {
459   lexer_p_->add_notename (s, m_p);
460 }
461
462 Paper_def*
463 My_lily_parser::default_paper_p ()
464 {
465         Identifier *id = lexer_p_->lookup_identifier ("default_paper");
466         return id ? id->paperdef () : new Paper_def ;
467 }
468
469 Midi_def*
470 My_lily_parser::default_midi_p ()
471 {
472         Identifier *id = lexer_p_->lookup_identifier ("default_midi");
473         return id ? id->mididef () : new Midi_def ;
474 }
475