]> git.donarmstrong.com Git - lilypond.git/blob - lily/my-lily-parser.cc
* lily/include/lily-guile.hh: is_x -> ly_c_X_p naming.
[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--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7        Jan Nieuwenhuizen <janneke@gnu.org>
8 */
9
10 #include "file-path.hh"
11 #include "lily-version.hh"
12 #include "ly-module.hh"
13 #include "ly-module.hh"
14 #include "main.hh"
15 #include "main.hh"
16 #include "my-lily-lexer.hh"
17 #include "my-lily-parser.hh"
18 #include "my-lily-parser.hh"
19 #include "paper-def.hh"
20 #include "parray.hh"
21 #include "parser.hh"
22 #include "scm-hash.hh"
23 #include "scm-hash.hh"
24 #include "score.hh"
25 #include "source.hh"
26 #include "string.hh"
27 #include "warn.hh"
28 #include "warn.hh"
29
30 My_lily_parser::My_lily_parser (Sources * sources)
31 {
32   book_count_ = 0;
33   score_count_ = 0;
34   lexer_ = 0;
35   sources_ = sources;
36   default_duration_ = Duration (2,0);
37   error_level_ = 0;
38   last_beam_start_ = SCM_EOL;
39
40   header_ = ly_make_anonymous_module ();
41 }
42
43 My_lily_parser::~My_lily_parser ()
44 {
45   delete lexer_;
46 }
47
48 /* Process one .ly file, or book.  */
49 void
50 My_lily_parser::parse_file (String init, String in_file, String out_file)
51 {
52   lexer_ = new My_lily_lexer (sources_);
53   output_basename_ = out_file;
54   
55   lexer_->main_input_name_ = in_file;
56
57   progress_indication (_ ("Parsing..."));
58   progress_indication ("\n");
59
60   set_yydebug (0);
61   lexer_->new_input (init, sources_);
62
63   /* Read .ly IN_FILE, lex, parse, write \score blocks from IN_FILE to
64      OUT_FILE (unless IN_FILE redefines output file name).  */
65   do_yyparse ();
66   
67   if (!define_spots_.is_empty ())
68     {
69       define_spots_.top ().warning (_ ("Braces don't match"));
70       error_level_ = 1;
71     }
72
73   // fixme: dependencies
74   //input_file_->inclusion_names_ = lexer_->filename_strings_;
75
76   error_level_ = error_level_ | lexer_->errorlevel_; // ugh naming.
77 }
78
79 void
80 My_lily_parser::push_spot ()
81 {
82   define_spots_.push (here_input ());
83 }
84
85 char const *
86 My_lily_parser::here_str0 () const
87 {
88   return lexer_->here_str0 ();
89 }
90
91 void
92 My_lily_parser::parser_error (String s)
93 {
94   here_input ().error (s);
95   error_level_ = 1;
96 }
97
98
99
100 Input
101 My_lily_parser::pop_spot ()
102 {
103   return define_spots_.pop ();
104 }
105
106 Input
107 My_lily_parser::here_input () const
108 {
109   /*
110     Parsing looks ahead , so we really want the previous location of the
111     lexer, not lexer_->here_input ().
112   */
113   /*
114     Actually, that gets very icky when there are white space, because
115     the line-numbers are all wrong.  Let's try the character before
116     the current token. That gets the right result for
117     note/duration stuff, but doesn't mess up for errors in the 1st token of the line. 
118     
119   */
120   Input hi (lexer_->here_input ());
121
122   char const * bla = hi.defined_str0_;
123   if (hi.line_number () > 1
124       || hi.column_number () > 1)
125     bla --;
126   
127   return Input (hi.source_file_, bla);
128 }
129
130
131 /****************************************************************/
132
133
134 /*
135   junkme?
136  */
137 bool store_locations_global_b;
138
139 /*
140   no ! suffix since it doesn't modify 1st argument.
141  */
142 LY_DEFINE (ly_set_point_and_click, "ly:set-point-and-click", 1, 0, 0,
143           (SCM what),
144           "Set the options for Point-and-click source specials output. The\n"
145 "argument is a symbol.  Possible options are @code{none} (no source specials),\n"
146 "@code{line} and @code{line-column}")
147 {
148   /*
149     UGH.
150    */
151   SCM val = SCM_BOOL_F;
152   if (ly_symbol2scm ("line-column") == what)
153     val = scm_c_eval_string ("line-column-location");
154   else if (what == ly_symbol2scm ("line"))
155     val = scm_c_eval_string ("line-location");
156
157   scm_module_define (global_lily_module, ly_symbol2scm ("point-and-click"), val);
158   store_locations_global_b = ly_c_procedure_p (val);
159   return SCM_UNSPECIFIED;
160 }
161
162
163 /* Distill full input file name from command argument.  PATH describes
164    file name with added default extension, ".ly" if none.  "-" is
165    STDIN.  */
166 Path
167 distill_inname (String str)
168 {
169   Path p = split_path (str);
170   if (str.is_empty () || str == "-")
171     p.base = "-";
172   else
173     {
174       String orig_ext = p.ext;
175       char const *extensions[] = {"ly", "", 0};
176       for (int i = 0; extensions[i]; i++)
177         {
178           p.ext = orig_ext;
179           if (*extensions[i] && !p.ext.is_empty ())
180             p.ext += ".";
181           p.ext += extensions[i];
182           if (!global_path.find (p.to_string ()).is_empty ())
183               break;
184         }
185       /* Reshuffle extension */
186       p = split_path (p.to_string ());
187     }
188   return p;
189 }
190
191 LY_DEFINE(ly_parse_file, "ly:parse-file",
192           1,0,0,
193           (SCM name),
194           "Parse a single @code{.ly} file. If this fails, then throw @code{ly-file-failed} key. "
195           )
196 {
197   SCM_ASSERT_TYPE (ly_c_string_p (name), name, SCM_ARG1, __FUNCTION__, "string");
198   char const *file = SCM_STRING_CHARS(name);
199   
200   String infile (file);
201   Path inpath = distill_inname (infile);
202   
203   /* By default, use base name of input file for output file name */
204   Path outpath = inpath;
205   if (inpath.to_string () != "-")
206     outpath.ext = output_format_global;
207   
208   /* By default, write output to cwd; do not copy directory part
209      of input file name */
210   outpath.root = "";
211   outpath.dir = "";
212   
213   if (!output_name_global.is_empty ())
214     outpath = split_path (output_name_global);
215   
216   String init;
217   if (!init_name_global.is_empty ())
218     init = init_name_global;
219   else
220     init = "init.ly";
221   
222   String in_file = inpath.to_string ();
223   String out_file = outpath.to_string ();
224
225
226   if (init.length () && global_path.find (init).is_empty ())
227     {
228       warning (_f ("can't find init file: `%s'", init));
229       warning (_f ("(search path: `%s')", global_path.to_string ().to_str0 ()));
230       exit (2);
231     }
232
233   if ((in_file != "-") && global_path.find (in_file).is_empty ())
234     {
235       warning (_f ("can't find file: `%s'", in_file));
236       scm_throw (ly_symbol2scm ("ly-file-failed"), scm_list_1 (scm_makfrom0str (in_file.to_str0 ())));
237     }
238   else
239     {
240       Sources sources;
241       sources.set_path (&global_path);
242   
243       progress_indication (_f ("Now processing `%s'", in_file.to_str0 ()));
244       progress_indication ("\n");
245
246       My_lily_parser parser (&sources);
247       parser.parse_file (init, in_file, out_file);
248   
249       if (parser.error_level_)
250         {
251           /*
252             TODO: pass renamed input file too.
253           */
254           scm_throw (ly_symbol2scm ("ly-file-failed"), scm_list_1 (scm_makfrom0str (in_file.to_str0 ()))); 
255         }
256     }
257   return SCM_UNSPECIFIED;
258 }
259