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 (My_lily_parser const &src)
44 book_count_ = src.book_count_;
45 score_count_ = src.score_count_;
47 sources_ = src.sources_;
48 default_duration_ = src.default_duration_;
49 error_level_ = src.error_level_;
50 last_beam_start_ = src.last_beam_start_;
51 header_ = src.header_;
56 My_lily_parser::~My_lily_parser ()
61 IMPLEMENT_SMOBS (My_lily_parser);
62 IMPLEMENT_TYPE_P (My_lily_parser, "ly:my-lily-parser?");
63 IMPLEMENT_DEFAULT_EQUAL_P (My_lily_parser);
66 My_lily_parser::mark_smob (SCM s)
68 My_lily_parser *parser = (My_lily_parser*) ly_cdr (s);
69 return parser->header_;
73 My_lily_parser::print_smob (SCM s, SCM port, scm_print_state*)
75 scm_puts ("#<my_lily_parser ", port);
76 My_lily_parser *parser = (My_lily_parser*) ly_cdr (s);
78 scm_puts (" >", port);
83 /* Process one .ly file, or book. */
85 My_lily_parser::parse_file (String init, String name, String out_name)
87 lexer_ = new My_lily_lexer (sources_);
88 output_basename_ = out_name;
90 lexer_->main_input_name_ = name;
92 progress_indication (_ ("Parsing..."));
93 progress_indication ("\n");
96 lexer_->new_input (init, sources_);
98 /* Read .ly IN_FILE, lex, parse, write \score blocks from IN_FILE to
99 OUT_FILE (unless IN_FILE redefines output file name). */
102 if (!define_spots_.is_empty ())
104 define_spots_.top ().warning (_ ("Braces don't match"));
108 error_level_ = error_level_ | lexer_->error_level_;
112 My_lily_parser::parse_string (String ly_code)
114 My_lily_lexer *parent = lexer_;
115 lexer_ = (parent == 0 ? new My_lily_lexer (sources_)
116 : new My_lily_lexer (*parent));
118 lexer_->main_input_name_ = "<string>";
119 lexer_->main_input_b_ = true;
122 lexer_->new_input (lexer_->main_input_name_, ly_code, sources_);
125 if (!define_spots_.is_empty ())
127 define_spots_.top ().warning (_ ("Braces don't match"));
131 error_level_ = error_level_ | lexer_->error_level_;
135 parent->keytable_ = lexer_->keytable_;
136 parent->encoding_ = lexer_->encoding_;
137 parent->chordmodifier_tab_ = lexer_->chordmodifier_tab_;
138 parent->pitchname_tab_stack_ = lexer_->pitchname_tab_stack_;
139 parent->sources_ = lexer_->sources_;
140 parent->scopes_ = lexer_->scopes_;
141 parent->error_level_ = lexer_->error_level_;
142 parent->main_input_b_ = lexer_->main_input_b_;
147 My_lily_parser::push_spot ()
149 define_spots_.push (here_input ());
153 My_lily_parser::here_str0 () const
155 return lexer_->here_str0 ();
159 My_lily_parser::parser_error (String s)
161 here_input ().error (s);
166 My_lily_parser::pop_spot ()
168 return define_spots_.pop ();
172 My_lily_parser::here_input () const
175 Parsing looks ahead , so we really want the previous location of the
176 lexer, not lexer_->here_input ().
179 Actually, that gets very icky when there are white space, because
180 the line-numbers are all wrong. Let's try the character before
181 the current token. That gets the right result for
182 note/duration stuff, but doesn't mess up for errors in the 1st token of the line.
185 Input hi (lexer_->here_input ());
187 char const * bla = hi.defined_str0_;
188 if (hi.line_number () > 1
189 || hi.column_number () > 1)
192 return Input (hi.source_file_, bla);
196 /****************************************************************/
202 bool store_locations_global_b;
204 /* Do not append `!' suffix, since 1st argument is not modified. */
205 LY_DEFINE (ly_set_point_and_click, "ly:set-point-and-click", 1, 0, 0,
207 "Set the options for Point-and-click source specials output. The\n"
208 "argument is a symbol. Possible options are @code{none} (no source specials),\n"
209 "@code{line} and @code{line-column}")
212 SCM val = SCM_BOOL_F;
213 if (ly_symbol2scm ("line-column") == what)
214 val = scm_c_eval_string ("line-column-location");
215 else if (what == ly_symbol2scm ("line"))
216 val = scm_c_eval_string ("line-location");
218 scm_module_define (global_lily_module, ly_symbol2scm ("point-and-click"),
220 store_locations_global_b = ly_c_procedure_p (val);
221 return SCM_UNSPECIFIED;
225 /* Distill full input file name from command argument. PATH describes
226 file name with added default extension, ".ly" if none. "-" is
229 distill_inname (String str)
231 Path p = split_path (str);
232 if (str.is_empty () || str == "-")
236 String orig_ext = p.ext;
237 char const *extensions[] = {"ly", "", 0};
238 for (int i = 0; extensions[i]; i++)
241 if (*extensions[i] && !p.ext.is_empty ())
243 p.ext += extensions[i];
244 if (!global_path.find (p.to_string ()).is_empty ())
247 /* Reshuffle extension */
248 p = split_path (p.to_string ());
253 LY_DEFINE (ly_parse_file, "ly:parse-file",
256 "Parse a single @code{.ly} file. "
257 "Upon failure, throw @code{ly-file-failed} key.")
259 SCM_ASSERT_TYPE (ly_c_string_p (name), name, SCM_ARG1, __FUNCTION__, "string");
260 char const *file = SCM_STRING_CHARS (name);
262 String infile (file);
263 Path inpath = distill_inname (infile);
265 /* By default, use base name of input file for output file name */
266 Path outpath = inpath;
267 if (inpath.to_string () != "-")
268 outpath.ext = output_format_global;
270 /* By default, write output to cwd; do not copy directory part
271 of input file name */
275 if (!output_name_global.is_empty ())
276 outpath = split_path (output_name_global);
279 if (!init_name_global.is_empty ())
280 init = init_name_global;
284 String in_file = inpath.to_string ();
285 String out_file = outpath.to_string ();
288 if (init.length () && global_path.find (init).is_empty ())
290 warning (_f ("can't find init file: `%s'", init));
291 warning (_f ("(search path: `%s')", global_path.to_string ().to_str0 ()));
295 if ((in_file != "-") && global_path.find (in_file).is_empty ())
297 warning (_f ("can't find file: `%s'", in_file));
298 scm_throw (ly_symbol2scm ("ly-file-failed"), scm_list_1 (scm_makfrom0str (in_file.to_str0 ())));
303 sources.set_path (&global_path);
305 progress_indication (_f ("Now processing `%s'", in_file.to_str0 ()));
306 progress_indication ("\n");
308 My_lily_parser *parser = new My_lily_parser (&sources);
309 scm_module_define (global_lily_module, ly_symbol2scm ("parser"),
310 parser->self_scm ());
311 parser->parse_file (init, in_file, out_file);
313 bool error = parser->error_level_;
316 /* TODO: pass renamed input file too. */
317 scm_throw (ly_symbol2scm ("ly-file-failed"),
318 scm_list_1 (scm_makfrom0str (in_file.to_str0 ())));
320 return SCM_UNSPECIFIED;
323 LY_DEFINE (ly_parse_string, "ly:parse-string",
326 "Parse the string LY_CODE. "
327 "Upon failure, throw @code{ly-file-failed} key.")
329 SCM_ASSERT_TYPE (ly_c_string_p (ly_code), ly_code, SCM_ARG1, __FUNCTION__, "string");
332 sources.set_path (&global_path);
333 My_lily_parser *parser = new My_lily_parser (&sources);
334 scm_module_define (global_lily_module, ly_symbol2scm ("parser"),
335 parser->self_scm ());
336 parser->parse_string (ly_scm2string (ly_code));
339 return SCM_UNSPECIFIED;
342 LY_DEFINE (ly_parser_parse_string, "ly:parser-parse-string",
344 (SCM parser_smob, SCM ly_code),
345 "Parse the string LY_CODE with PARSER_SMOB."
346 "Upon failure, throw @code{ly-file-failed} key.")
349 SCM_ASSERT_TYPE (ly_c_parser_p (parser), music, SCM_ARG1, __FUNCTION__, "parser");
351 SCM_ASSERT_TYPE (ly_c_string_p (ly_code), ly_code, SCM_ARG1, __FUNCTION__, "string");
354 My_lily_parser *parser = unsmob_my_lily_parser (parser_smob);
355 parser->parse_string (ly_scm2string (ly_code));
357 My_lily_parser *parser = unsmob_my_lily_parser (parser_smob);
358 My_lily_parser *clone = new My_lily_parser (*parser);
359 clone->parse_string (ly_scm2string (ly_code));
363 return SCM_UNSPECIFIED;
366 static Music_output_def*
367 get_paper (My_lily_parser *parser)
369 SCM id = parser->lexer_->lookup_identifier ("$defaultpaper");
370 Music_output_def *paper = unsmob_music_output_def (id);
371 return paper ? paper->clone () : new Paper_def;
374 LY_DEFINE (ly_parser_print_score, "ly:parser-print-score",
376 (SCM parser_smob, SCM score_smob),
377 "Print score, i.e., the classic way.")
380 SCM_ASSERT_TYPE (ly_c_parser_p (parser), music, SCM_ARG1, __FUNCTION__, "parser");
381 SCM_ASSERT_TYPE (ly_c_music_p (music), music, SCM_ARG1, __FUNCTION__, "music");
383 My_lily_parser *parser = unsmob_my_lily_parser (parser_smob);
384 Score *score = unsmob_score (score_smob);
386 SCM header = is_module (score->header_) ? score->header_
387 : parser->header_.to_SCM ();
389 Path outname = split_path (parser->output_basename_);
390 int *c = &parser->book_count_;
392 outname.base += "-" + to_string (*c);
395 SCM os = scm_makfrom0str (outname.to_string ().to_str0 ());
396 for (int i = 0; i < score->defs_.size (); i++)
397 default_rendering (score->music_, score->defs_[i]->self_scm (), header,
400 if (score->defs_.is_empty ())
402 Music_output_def *paper = get_paper (parser);
403 default_rendering (score->music_, paper->self_scm (), header, os);
404 scm_gc_unprotect_object (paper->self_scm ());
406 return SCM_UNDEFINED;
409 LY_DEFINE (ly_parser_print_book, "ly:parser-print-book",
411 (SCM parser_smob, SCM book_smob),
415 SCM_ASSERT_TYPE (ly_c_parser_p (parser_smob), parser_smob, SCM_ARG1, __FUNCTION__, "parser_smob");
416 SCM_ASSERT_TYPE (ly_c_music_p (book_smob), book_smob, SCM_ARG1, __FUNCTION__, "book_smob");
418 My_lily_parser *parser = unsmob_my_lily_parser (parser_smob);
419 Book *book = unsmob_book (book_smob);
421 SCM header = parser->header_;
422 Path outname = split_path (parser->output_basename_);
423 int *c = &parser->book_count_;
425 outname.base += "-" + to_string (*c);
427 Music_output_def *paper = get_paper (parser);
428 book->process (outname.to_string (), paper, header);
429 scm_gc_unprotect_object (paper->self_scm ());
430 return SCM_UNDEFINED;