]> git.donarmstrong.com Git - lilypond.git/blob - src/parser.y
release: 0.0.23
[lilypond.git] / src / parser.y
1 %{ // -*-Fundamental-*-
2 #include <iostream.h>
3
4 #include "lookup.hh"
5 #include "misc.hh"
6 #include "lexer.hh"
7 #include "paper.hh"
8 #include "inputscore.hh"
9 #include "main.hh"
10 #include "keyword.hh"
11 #include "inputcommand.hh"
12 #include "debug.hh"
13 #include "parseconstruct.hh"
14 #include "dimen.hh"
15 #include "identifier.hh"
16
17 #ifndef NDEBUG
18 #define YYDEBUG 1
19 #endif
20
21 Array<Request*> pre_reqs, post_reqs;
22 sstack<String> define_spots;
23
24 Paperdef*default_paper();
25 %}
26
27
28 %union {
29     Request * request;
30     Real real;
31     Input_command *command;
32     Identifier *id;    
33     Voice *voice;    
34     Voice_element *el;  
35     String *string;
36     const char *consstr;
37     Paperdef *paper;
38     Input_music *music;
39     Music_general_chord *chord;
40     Music_voice *mvoice; 
41     int i;
42     char c;
43     int ii[10];
44         Moment *moment;
45
46     Array<String> * strvec;
47     Array<Input_command*> *commandvec;
48     Array<int> *intvec;
49
50     Input_staff *staff;    
51     Input_score *score;
52     Symtables * symtables;
53     Symtable * symtable;
54     Symbol * symbol;
55     Lookup*lookup;
56     Interval *interval;
57     Box *box;
58     Notename_tab *notename_tab;
59     Script_def * script;
60     Text_def * textdef;
61 }
62
63 %token VOICE STAFF SCORE TITLE  BAR NOTENAME OUTPUT
64 %token CM IN PT MM PAPER WIDTH METER UNITSPACE SKIP COMMANDS
65 %token GEOMETRIC START_T DURATIONCOMMAND OCTAVECOMMAND
66 %token KEY CLEF VIOLIN BASS MULTI TABLE CHORD VOICES
67 %token PARTIAL RHYTHMIC MELODIC MUSIC GROUPING CADENZA
68 %token END SYMBOLTABLES TEXID TABLE NOTENAMES SCRIPT TEXTSTYLE PLET
69 %token MARK GOTO
70
71 %token <id>  IDENTIFIER
72 %token <string> NEWIDENTIFIER 
73 %token <string> PITCHMOD DURATION RESTNAME
74 %token <ii> NOTENAME 
75 %token <real> REAL
76 %token <string> STRING
77
78 %token <i> DOTS INT
79 %type <consstr> unit
80 %type <intvec> pitch_list
81 %type <c> open_request_parens close_request_parens
82 %type <id> declaration
83 %type <string> declarable_identifier
84 %type <paper> paper_block paper_body
85 %type <real> dim
86 %type <ii> duration
87 %type <moment> duration_length
88 %type <el> voice_elt full_element
89 %type <command> score_command staff_command skipcommand
90 %type <score> score_block score_body
91 %type <staff> staff_block staff_init staff_body
92 %type <i> int
93 %type <intvec> int_list
94 %type <commandvec> score_commands_block score_commands_body
95 %type <commandvec> staff_commands_block staff_commands_body
96 %type <request> post_request pre_request 
97 %type <string> clef_id pitchmod
98 %type <music> music 
99 %type <chord> music_chord music_chord_body
100
101 %type <mvoice>  music_voice_body music_voice
102
103 %type <interval> dinterval
104 %type <box> box
105 %type <symtable> symtable symtable_body
106 %type <lookup> symtables symtables_body
107 %type <symbol> symboldef
108 %type <notename_tab> notename_tab notename_tab_body
109 %type <i> script_dir
110 %type <script> script_definition script_body mudela_script
111 %type <request> script_req textscript_req
112 %type <textdef> mudela_text
113
114
115 %%
116
117 mudela: /* empty */
118         | mudela score_block { 
119                 add_score($2);
120         }
121         | mudela add_declaration { }
122         | mudela mudela_command  {}
123         ;
124
125 mudela_command:
126         notename_tab                    { lexer->set($1); }
127         ;
128
129 /*
130         DECLARATIONS
131 */
132 add_declaration: declaration    {
133                 lexer->add_identifier($1);
134         }
135         ;
136
137 declarable_identifier:
138         NEWIDENTIFIER { $$ = $1; }
139         | IDENTIFIER { $$ = new String($1->name); }
140         ;
141
142 declaration:
143         declarable_identifier '=' staff_block  {
144                 $$ = new Staff_id(*$1, $3);
145                 delete $1; // this sux
146         }
147         | declarable_identifier '=' music_voice {
148                 $$ = new M_voice_id(*$1, $3);
149                 delete $1;
150         }
151         | declarable_identifier '=' script_definition {
152                 $$ = new Script_id(*$1, $3);
153                 delete $1;
154         }
155         | declarable_identifier '=' music_chord  {
156                 $$ = new M_chord_id(*$1, $3);
157                 delete $1;
158         }
159         | declarable_identifier '=' symtables {
160                 $$ = new Lookup_id(*$1, $3);
161                 delete $1;
162         }
163         | declarable_identifier '=' notename_tab {
164                 $$ = new Notetab_id(*$1, $3);
165                 delete $1;
166         }
167         ;
168
169 notename_tab:
170         NOTENAMES '{' notename_tab_body '}'     { $$ = $3; }
171         ;
172
173 notename_tab_body:                              {
174                 $$ = new Notename_tab;
175         }
176         | IDENTIFIER                            {
177                 $$ = $1->notename_tab(true);
178         }
179         | notename_tab_body STRING int int                      {
180                 $$->set($3, $4, *$2);
181                 delete $2;
182         }
183         ;
184
185 /*
186         SCORE
187 */
188 score_block: SCORE 
189                 { define_spots.push(lexer->spot()); }
190         '{' score_body '}'      {
191                 $$ = $4;
192                 $$->define_spot_str_ = define_spots.pop();
193                 if (!$$->paper_)
194                         $$->paper_ = default_paper();
195         }
196         ;
197
198 score_body:             { $$ = new Input_score; }
199         | score_body staff_block        { $$->add($2); }
200         | score_body score_commands_block       {
201                 $$->add(*$2);
202                 delete $2;
203         }
204         | score_body paper_block                { $$->set($2);  }
205         ;
206 /*
207         COMMANDS
208 */
209 score_commands_block:
210         COMMANDS '{' score_commands_body '}' { $$ =$3;}
211         ;
212
213 score_commands_body:                    { $$ = new Array<Input_command*>; }
214         | score_commands_body score_command             {
215                 $$->add($2);
216         }
217         ;
218
219 staff_commands_block: COMMANDS '{' staff_commands_body '}'      {       
220                 $$ = $3; }
221         ;
222
223 staff_commands_body:
224         /* empty */                     { $$ = new Array<Input_command*>; }
225         | staff_commands_body staff_command     {
226                 $$->add($2);
227         }
228         ;
229
230 staff_command:
231         skipcommand
232         | KEY pitch_list        {/*UGH*/
233                 $$ = get_key_interpret_command(*$2);
234                 delete $2;
235         }
236         | CLEF clef_id                  {
237                 $$ = get_clef_interpret_command(*$2);
238                 delete $2;
239         }
240         ;
241
242 duration_length:        
243         duration                {
244                 $$ = new Moment(wholes($1[0], $1[1]));
245         }
246         |int '*' duration       {
247                 $$ = new Moment($1 * wholes($3[0], $3[1]));
248         }
249         ;
250
251 skipcommand:
252         SKIP int ':' duration_length            {
253                 $$ = get_skip_command($2, *$4);
254                 delete $4;
255         }
256         | GOTO STRING   {
257                 $$ = get_goto_command(*$2);
258                 delete $2;
259         }
260
261 score_command:
262         skipcommand
263         | BAR STRING                    {
264                 $$ = get_bar_command(*$2);
265                 delete $2;
266         }
267         | METER  int '*' int            {
268                 $$ = get_meterchange_command($2, $4);
269         }
270         | PARTIAL duration_length               {
271                 $$ = get_partial_command(*$2);
272                 delete $2;
273         }
274         | GROUPING int_list             {
275                 $$ = get_grouping_command(*$2);
276                 delete $2;
277         }
278         | CADENZA int   {
279                 $$ = get_cadenza_toggle($2);
280         }
281         ;
282
283
284
285 /*
286         PAPER
287 */
288 paper_block:
289         PAPER
290
291         '{' paper_body '}'      { $$ = $3; }
292         ;
293
294 paper_body:
295         /* empty */                     {
296                 $$ = default_paper();
297         }
298         | paper_body WIDTH dim          { $$->linewidth = $3;}
299         | paper_body OUTPUT STRING      { $$->outfile = *$3;
300                 delete $3;
301         }
302         | paper_body symtables          { $$->set($2); }
303         | paper_body UNITSPACE dim      { $$->whole_width = $3; }
304         | paper_body GEOMETRIC REAL     { $$->geometric_ = $3; }
305         ;
306
307 /*
308         STAFFs
309 */
310 staff_block:
311         STAFF   { define_spots.push(lexer->spot()); }
312 /*cont*/        '{' staff_body '}'      {
313                 $$ = $4; 
314                 $$->define_spot_str_ = define_spots.pop();
315         }
316         ;
317
318
319
320 staff_init:
321         IDENTIFIER              { $$ = $1->staff(true); }
322         | RHYTHMIC              {
323                 $$ = new Input_staff("rhythmic");
324         }
325         | MELODIC               {
326                 $$ = new Input_staff( "melodic");
327         }
328         ;
329
330 staff_body:
331         staff_init
332         | staff_body music      {
333                 $$->add($2);
334         }
335         | staff_body staff_commands_block {
336                 $$->add(*$2);
337                 delete $2;
338         }
339         ;
340
341 /*
342         MUSIC
343 */
344 music:
345         music_voice     { $$ = $1; }
346         | music_chord   { $$ = $1; }
347         ;
348
349 music_voice:  MUSIC '{' music_voice_body '}'    { $$ = $3; }
350         ;
351
352 music_voice_body:                       {
353                 $$ = new Music_voice;
354         }
355         | music_voice_body IDENTIFIER {
356                 $$->concatenate($2->mvoice());
357         }
358         | music_voice_body full_element {
359                 $$->add_elt($2);
360         }
361         | music_voice_body voice_command {
362         }
363         | music_voice_body music        {
364                 $$->add($2);
365         }
366         ;
367
368
369 music_chord:  '{' music_chord_body '}'  { $$ = $2; }
370         ;
371
372 music_chord_body:               {
373                 $$ = new Music_general_chord;
374         }
375         | music_chord_body IDENTIFIER {
376                 $$->concatenate($2->mchord());
377         }
378         | music_chord_body music {
379                 $$ -> add($2);
380         }
381         | music_chord_body full_element {
382                 $$ ->add_elt($2);
383         }
384         ;
385
386
387
388 /*
389         VOICE ELEMENTS
390 */
391 full_element:   pre_requests voice_elt post_requests {
392                 add_requests($2, pre_reqs);
393                 add_requests($2, post_reqs);
394                 $$ = $2;
395         }
396         ;
397
398 post_requests:
399         {
400                 assert(post_reqs.empty());
401         }
402         | post_requests post_request {
403                 post_reqs.add($2);
404         }
405         ;
406
407 post_request:
408         close_request_parens            { $$ = get_request($1); }
409         | script_req
410         | textscript_req
411         ;
412 close_request_parens:
413         '('     { $$='('; }
414         |']'    { $$ = ']' }
415         ;
416
417 open_request_parens:
418         '|'     {$$='|'}
419         |')'    {$$=')'}
420         |'['    {$$='['}
421         ;
422
423 script_definition:
424         SCRIPT '{' script_body '}'      { $$ = $3; }
425         ;
426
427 script_body:
428         STRING int int int              {
429                 $$ = new Script_def(*$1,$2, $3,$4);
430                 delete $1;
431         }       
432         ;
433
434 textscript_req:
435         script_dir mudela_text          { $$ = get_text_req($1,$2); }
436         ;
437
438 mudela_text:
439         STRING                  { $$ = get_text(*$1); delete $1; }
440         ;
441
442 script_req:
443         script_dir mudela_script        { $$ = get_script_req($1, $2); }
444         ;
445
446 mudela_script:
447         IDENTIFIER              { $$ = $1->script(true); }
448         | script_definition             { $$ = $1; }
449         | '^'           { $$ = get_scriptdef('^'); }
450         | '+'           { $$ = get_scriptdef('+'); }
451         | '-'           { $$ = get_scriptdef('-'); }
452         | '|'           { $$ = get_scriptdef('|'); }
453         | 'o'           { $$ = get_scriptdef('o'); }
454         | '>'           { $$ = get_scriptdef('>'); }
455         | '.'           { $$ = get_scriptdef('.'); }
456         | DOTS          {
457                 if ($1>1) error("too many staccato reqs");
458                 $$ = get_scriptdef('.');
459         }
460         ;
461
462 script_dir:
463         '_'     { $$ = -1; }
464         |'^'    { $$ = 1; }
465         |'-'    { $$ = 0; }
466         ;
467
468 pre_requests:
469         | pre_requests pre_request {
470                 pre_reqs.add($2);
471         }
472         ;
473
474 pre_request: 
475         open_request_parens             { $$ = get_request($1); }
476         ;
477
478
479
480 voice_command:
481         PLET    '{' INT '/' INT '}'             {
482                 set_plet($3,$5);
483         }
484         | DURATIONCOMMAND '{' duration '}'      {
485                 set_default_duration($3);
486         }
487         | OCTAVECOMMAND '{' pitchmod '}'        {
488                 set_default_octave(*$3);
489                 delete $3;
490         }
491         | TEXTSTYLE STRING      {
492                 set_text_style(*$2);
493                 delete $2;
494         }
495         ;
496
497 duration:               {
498                 get_default_duration($$);
499         }
500         | int           {
501                 get_default_duration($$);
502                 $$[0] = $1;
503                 $$[1] = 0;
504         }
505         | int DOTS      {
506                 $$[0] = $1;
507                 $$[1] = $2;
508         }
509         | DOTS  {
510                 get_default_duration($$);
511                 $$[1] = $1;
512         }
513         ;
514
515 pitchmod:               { $$ = new String; }
516         |PITCHMOD       
517         ;
518
519 voice_elt:
520         pitchmod NOTENAME duration                      {
521                 $$ = get_note_element(*$1, $2, $3);
522                 delete $1;
523         }
524         | RESTNAME duration             {
525                 $$ = get_rest_element(*$1, $2);
526                 delete $1;
527
528         }
529         | MARK STRING   {
530                 $$ = get_mark_element(*$2);
531                 delete $2;
532         }
533         ;
534
535 /*
536         UTILITIES
537 */
538 pitch_list:                     {
539                 $$ = new Array<int>;
540         }
541         | pitch_list NOTENAME   {
542                 $$->add($2[0]);
543                 $$->add($2[1]);         
544         }
545         ;
546
547 int:
548         REAL                    {
549                 $$ = int($1);
550                 if ( distance($1,Real(int($$)) ) > 1e-8)
551                         error("expecting integer number");
552         }
553         | INT
554         ;
555
556 int_list:
557         /* */           {
558                 $$ = new Array<int>;
559         }
560         | int_list int          {
561                 $$->add($2);
562         }
563         ;
564
565 dim:
566         REAL unit       { $$ = convert_dimen($1,$2); }
567         ;
568
569
570 unit:   CM              { $$ = "cm"; }
571         |IN             { $$ = "in"; }
572         |MM             { $$ = "mm"; }
573         |PT             { $$ = "pt"; }
574         ;
575         
576 clef_id:
577         VIOLIN          { $$ = new String("violin"); }
578         | BASS          { $$ = new String("bass"); }
579         ;
580 /*
581         symbol tables
582 */
583 symtables:
584         SYMBOLTABLES '{' symtables_body '}'     { $$ = $3; }
585         ;
586
587 symtables_body:
588                         {
589                 $$ = new Lookup;
590         }
591         | IDENTIFIER            {
592                 $$ = new Lookup(*$1->lookup(true));
593         }
594         | symtables_body TEXID STRING           {
595                 $$->texsetting = *$3;
596                 delete $3;
597         }
598         | symtables_body STRING '=' symtable            {
599                 $$->add(*$2, $4);
600                 delete $2;
601         }
602         ;
603
604 symtable:
605         TABLE '{' symtable_body '}' { $$ = $3; }
606         ;
607
608 symtable_body:
609                                 { $$ = new Symtable; }
610         | symtable_body STRING  symboldef {
611                 $$->add(*$2, *$3);
612                 delete $2;
613                 delete $3;
614         }
615         ;
616
617 symboldef:
618         STRING  box             {
619                 $$ = new Symbol(*$1, *$2);
620                 delete $1;
621                 delete $2;
622         }
623         | STRING {
624                 Box b;
625                 $$ = new Symbol(*$1, b);
626                 delete $1;
627         }
628         ;
629
630 box:
631         dinterval dinterval     {
632                 $$ = new Box(*$1, *$2);
633                 delete $1;
634                 delete $2;
635         }
636         ;
637
638 dinterval: dim  dim             {
639                 $$ = new Interval($1, $2);      
640         }
641         ;
642
643 %%
644
645 void
646 parse_file(String s)
647 {
648    *mlog << "Parsing ... ";
649
650 #ifdef YYDEBUG
651    yydebug = !monitor.silence("Parser") && check_debug;
652 #endif
653
654    set_lexer();
655    lexer->new_input("symbol.ini");
656    yyparse();
657    lexer->new_input(s);
658    yyparse();
659    kill_lexer();
660    assert(define_spots.empty());
661 }
662
663 Paperdef*
664 default_paper()
665 {
666     return new Paperdef(
667         lexer->lookup_identifier("default_table")->lookup(true));
668 }