2 my-lily-parser.cc -- implement My_lily_parser
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 Jan Nieuwenhuizen <janneke@gnu.org>
11 #include "file-path.hh"
12 #include "lily-version.hh"
13 #include "ly-module.hh"
14 #include "ly-smobs.icc"
16 #include "my-lily-lexer.hh"
17 #include "my-lily-parser.hh"
18 #include "paper-def.hh"
21 #include "scm-hash.hh"
27 My_lily_parser::My_lily_parser (Sources *sources)
33 default_duration_ = Duration (2,0);
35 last_beam_start_ = SCM_EOL;
38 header_ = ly_make_anonymous_module ();
42 My_lily_parser::~My_lily_parser ()
47 IMPLEMENT_SMOBS (My_lily_parser);
48 IMPLEMENT_TYPE_P (My_lily_parser, "ly:my-lily-parser?");
49 IMPLEMENT_DEFAULT_EQUAL_P (My_lily_parser);
52 My_lily_parser::mark_smob (SCM s)
54 My_lily_parser *parser = (My_lily_parser*) ly_cdr (s);
55 return parser->header_;
59 My_lily_parser::print_smob (SCM s, SCM port, scm_print_state*)
61 scm_puts ("#<my_lily_parser ", port);
62 My_lily_parser *parser = (My_lily_parser*) ly_cdr (s);
64 scm_puts (" >", port);
69 /* Process one .ly file, or book. */
71 My_lily_parser::parse_file (String init, String name, String out_name)
73 lexer_ = new My_lily_lexer (sources_);
74 output_basename_ = out_name;
76 lexer_->main_input_name_ = name;
78 progress_indication (_ ("Parsing..."));
79 progress_indication ("\n");
82 lexer_->new_input (init, sources_);
84 /* Read .ly IN_FILE, lex, parse, write \score blocks from IN_FILE to
85 OUT_FILE (unless IN_FILE redefines output file name). */
88 if (!define_spots_.is_empty ())
90 define_spots_.top ().warning (_ ("Braces don't match"));
94 error_level_ = error_level_ | lexer_->error_level_;
98 My_lily_parser::parse_string (String ly_code)
100 lexer_ = new My_lily_lexer (sources_);
101 lexer_->main_input_name_ = "<string>";
102 lexer_->main_input_b_ = true;
105 lexer_->new_input (lexer_->main_input_name_, ly_code, sources_);
108 if (!define_spots_.is_empty ())
110 define_spots_.top ().warning (_ ("Braces don't match"));
114 error_level_ = error_level_ | lexer_->error_level_;
118 My_lily_parser::push_spot ()
120 define_spots_.push (here_input ());
124 My_lily_parser::here_str0 () const
126 return lexer_->here_str0 ();
130 My_lily_parser::parser_error (String s)
132 here_input ().error (s);
139 My_lily_parser::pop_spot ()
141 return define_spots_.pop ();
145 My_lily_parser::here_input () const
148 Parsing looks ahead , so we really want the previous location of the
149 lexer, not lexer_->here_input ().
152 Actually, that gets very icky when there are white space, because
153 the line-numbers are all wrong. Let's try the character before
154 the current token. That gets the right result for
155 note/duration stuff, but doesn't mess up for errors in the 1st token of the line.
158 Input hi (lexer_->here_input ());
160 char const * bla = hi.defined_str0_;
161 if (hi.line_number () > 1
162 || hi.column_number () > 1)
165 return Input (hi.source_file_, bla);
169 /****************************************************************/
175 bool store_locations_global_b;
177 /* Do not append `!' suffix, since 1st argument is not modified. */
178 LY_DEFINE (ly_set_point_and_click, "ly:set-point-and-click", 1, 0, 0,
180 "Set the options for Point-and-click source specials output. The\n"
181 "argument is a symbol. Possible options are @code{none} (no source specials),\n"
182 "@code{line} and @code{line-column}")
185 SCM val = SCM_BOOL_F;
186 if (ly_symbol2scm ("line-column") == what)
187 val = scm_c_eval_string ("line-column-location");
188 else if (what == ly_symbol2scm ("line"))
189 val = scm_c_eval_string ("line-location");
191 scm_module_define (global_lily_module, ly_symbol2scm ("point-and-click"),
193 store_locations_global_b = ly_c_procedure_p (val);
194 return SCM_UNSPECIFIED;
198 /* Distill full input file name from command argument. PATH describes
199 file name with added default extension, ".ly" if none. "-" is
202 distill_inname (String str)
204 Path p = split_path (str);
205 if (str.is_empty () || str == "-")
209 String orig_ext = p.ext;
210 char const *extensions[] = {"ly", "", 0};
211 for (int i = 0; extensions[i]; i++)
214 if (*extensions[i] && !p.ext.is_empty ())
216 p.ext += extensions[i];
217 if (!global_path.find (p.to_string ()).is_empty ())
220 /* Reshuffle extension */
221 p = split_path (p.to_string ());
226 LY_DEFINE (ly_parse_file, "ly:parse-file",
229 "Parse a single @code{.ly} file. "
230 "Upon failure, throw @code{ly-file-failed} key.")
232 SCM_ASSERT_TYPE (ly_c_string_p (name), name, SCM_ARG1, __FUNCTION__, "string");
233 char const *file = SCM_STRING_CHARS (name);
235 String infile (file);
236 Path inpath = distill_inname (infile);
238 /* By default, use base name of input file for output file name */
239 Path outpath = inpath;
240 if (inpath.to_string () != "-")
241 outpath.ext = output_format_global;
243 /* By default, write output to cwd; do not copy directory part
244 of input file name */
248 if (!output_name_global.is_empty ())
249 outpath = split_path (output_name_global);
252 if (!init_name_global.is_empty ())
253 init = init_name_global;
257 String in_file = inpath.to_string ();
258 String out_file = outpath.to_string ();
261 if (init.length () && global_path.find (init).is_empty ())
263 warning (_f ("can't find init file: `%s'", init));
264 warning (_f ("(search path: `%s')", global_path.to_string ().to_str0 ()));
268 if ((in_file != "-") && global_path.find (in_file).is_empty ())
270 warning (_f ("can't find file: `%s'", in_file));
271 scm_throw (ly_symbol2scm ("ly-file-failed"), scm_list_1 (scm_makfrom0str (in_file.to_str0 ())));
276 sources.set_path (&global_path);
278 progress_indication (_f ("Now processing `%s'", in_file.to_str0 ()));
279 progress_indication ("\n");
281 My_lily_parser *parser = new My_lily_parser (&sources);
282 scm_module_define (global_lily_module, ly_symbol2scm ("parser"),
283 parser->self_scm ());
284 parser->parse_file (init, in_file, out_file);
286 bool error = parser->error_level_;
289 /* TODO: pass renamed input file too. */
290 scm_throw (ly_symbol2scm ("ly-file-failed"),
291 scm_list_1 (scm_makfrom0str (in_file.to_str0 ())));
293 return SCM_UNSPECIFIED;
296 LY_DEFINE (ly_parse_string, "ly:parse-string",
299 "Parse the string LY_CODE. "
300 "Upon failure, throw @code{ly-file-failed} key.")
302 SCM_ASSERT_TYPE (ly_c_string_p (ly_code), ly_code, SCM_ARG1, __FUNCTION__, "string");
305 sources.set_path (&global_path);
306 My_lily_parser *parser = new My_lily_parser (&sources);
307 scm_module_define (global_lily_module, ly_symbol2scm ("parser"),
308 parser->self_scm ());
309 parser->parse_string (ly_scm2string (ly_code));
312 return SCM_UNSPECIFIED;
315 LY_DEFINE (ly_parser_parse_string, "ly:parser-parse-string",
317 (SCM parser_smob, SCM ly_code),
318 "Parse the string LY_CODE with PARSER_SMOB."
319 "Upon failure, throw @code{ly-file-failed} key.")
322 SCM_ASSERT_TYPE (ly_c_parser_p (parser), music, SCM_ARG1, __FUNCTION__, "parser");
324 SCM_ASSERT_TYPE (ly_c_string_p (ly_code), ly_code, SCM_ARG1, __FUNCTION__, "string");
327 My_lily_parser *parser = unsmob_my_lily_parser (parser_smob);
329 /* New parser, copy vars but no state? */
331 parser->parse_string (ly_scm2string (ly_code));
333 return SCM_UNSPECIFIED;
336 static Music_output_def*
337 get_paper (My_lily_parser *parser)
339 SCM id = parser->lexer_->lookup_identifier ("$defaultpaper");
340 Music_output_def *paper = unsmob_music_output_def (id);
341 return paper ? paper->clone () : new Paper_def;
344 LY_DEFINE (ly_parser_print_score, "ly:parser-print-score",
346 (SCM parser_smob, SCM score_smob),
347 "Print score, i.e., the classic way.")
350 SCM_ASSERT_TYPE (ly_c_parser_p (parser), music, SCM_ARG1, __FUNCTION__, "parser");
351 SCM_ASSERT_TYPE (ly_c_music_p (music), music, SCM_ARG1, __FUNCTION__, "music");
353 My_lily_parser *parser = unsmob_my_lily_parser (parser_smob);
354 Score *score = unsmob_score (score_smob);
356 SCM header = is_module (score->header_) ? score->header_
357 : parser->header_.to_SCM ();
359 Path outname = split_path (parser->output_basename_);
360 int *c = &parser->book_count_;
362 outname.base += "-" + to_string (*c);
365 SCM os = scm_makfrom0str (outname.to_string ().to_str0 ());
366 for (int i = 0; i < score->defs_.size (); i++)
367 default_rendering (score->music_, score->defs_[i]->self_scm (), header,
370 if (score->defs_.is_empty ())
372 Music_output_def *paper = get_paper (parser);
373 default_rendering (score->music_, paper->self_scm (), header, os);
374 scm_gc_unprotect_object (paper->self_scm ());
376 return SCM_UNDEFINED;
379 LY_DEFINE (ly_parser_print_book, "ly:parser-print-book",
381 (SCM parser_smob, SCM book_smob),
385 SCM_ASSERT_TYPE (ly_c_parser_p (parser_smob), parser_smob, SCM_ARG1, __FUNCTION__, "parser_smob");
386 SCM_ASSERT_TYPE (ly_c_music_p (book_smob), book_smob, SCM_ARG1, __FUNCTION__, "book_smob");
388 My_lily_parser *parser = unsmob_my_lily_parser (parser_smob);
389 Book *book = unsmob_book (book_smob);
391 SCM header = parser->header_;
392 Path outname = split_path (parser->output_basename_);
393 int *c = &parser->book_count_;
395 outname.base += "-" + to_string (*c);
397 Music_output_def *paper = get_paper (parser);
398 book->process (outname.to_string (), paper, header);
399 scm_gc_unprotect_object (paper->self_scm ());
400 return SCM_UNDEFINED;