X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Flexer.ll;h=e07648fc32acefee31c836a4823fc618abf50b66;hb=11591464d14470386146df7a4c33998b53dbd35c;hp=7e09d03e58d9f6a8cc50e29af79b9e986ae31842;hpb=95de6911a5cd1f90dfcd72ec798f089f6522f50f;p=lilypond.git diff --git a/lily/lexer.ll b/lily/lexer.ll index 7e09d03e58..e07648fc32 100644 --- a/lily/lexer.ll +++ b/lily/lexer.ll @@ -4,7 +4,8 @@ source file of the LilyPond music typesetter - (c) 1996,1997 Han-Wen Nienhuys + (c) 1996--2000 Han-Wen Nienhuys + Jan Nieuwenhuizen */ @@ -17,35 +18,65 @@ lex.backup contains no backup states, but only the reminder Compressed tables always back up. - (don-t forget to rm lex.yy.cc :-) + (don-t forget to rm lex.yy.cc :-) */ #include #include +#include /* gcc 3.0 */ +#include + +#include "score.hh" +#include "lily-guile.hh" #include "string.hh" #include "string-convert.hh" #include "my-lily-lexer.hh" -#include "varray.hh" +#include "array.hh" #include "interval.hh" +#include "lily-guile.hh" #include "parser.hh" #include "debug.hh" -#include "parseconstruct.hh" #include "main.hh" #include "musical-request.hh" -#include "identifier.hh" +#include "version.hh" +#include "lilypond-input-version.hh" +#include "translator-def.hh" +#include "music-output-def.hh" + +/* +RH 7 fix (?) +*/ +#define isatty HORRIBLEKLUDGE + void strip_trailing_white (String&); void strip_leading_white (String&); +String lyric_fudge (String s); + + +bool +valid_version_b (String s); + #define start_quote() \ yy_push_state (quote);\ yylval.string = new String -#define yylval (*(YYSTYPE*)lexval_l) +#define yylval \ + (*(YYSTYPE*)lexval_l) #define YY_USER_ACTION add_lexed_char (YYLeng ()); +/* + +LYRICS ({AA}|{TEX})[^0-9 \t\n\f]* + +*/ + + +SCM scan_fraction (String); + %} %option c++ @@ -57,9 +88,12 @@ void strip_leading_white (String&); %option never-interactive %option warn +%x version +%x chords %x incl %x lyrics %x notes +%x figures %x quote %x longcomment @@ -68,27 +102,27 @@ A [a-zA-Z] AA {A}|_ N [0-9] AN {AA}|{N} -PUNCT [?!:'] +PUNCT [?!:'`] ACCENT \\[`'"^] -NATIONAL [\001-\006\021-\027\031\036\200-\377] +NATIONAL [\001-\006\021-\027\031\036\200-\377] TEX {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL} WORD {A}{AN}* ALPHAWORD {A}+ DIGIT {N} UNSIGNED {N}+ +FRACTION {N}+\/{N}+ INT -?{UNSIGNED} REAL ({INT}\.{N}*)|(-?\.{N}+) KEYWORD \\{WORD} -WHITE [ \n\t\f] +WHITE [ \n\t\f\r] HORIZONTALWHITE [ \t] -BLACK [^ \n\t\f] +BLACK [^ \n\t\f\r] RESTNAME [rs] NOTECOMMAND \\{A}+ LYRICS ({AA}|{TEX})[^0-9 \t\n\f]* ESCAPED [nt\\'"] -PLET \\\[ -TELP \\\] - +EXTENDER __ +HYPHEN -- %% @@ -96,7 +130,7 @@ TELP \\\] // windows-suck-suck-suck } -{ +{ "%{" { yy_push_state (longcomment); } @@ -113,6 +147,21 @@ TELP \\\] } } +\\version{WHITE}* { + yy_push_state (version); +} +\"[^"]*\" { /* got the version number */ + String s (YYText ()+1); + s = s.left_str (s.index_last_i ('"')); + + yy_pop_state (); + if (!valid_version_b (s)) + return INVALID; +} +. { + LexerError ("No quoted string found after \\version"); + yy_pop_state (); +} { [^\%]* { } @@ -123,85 +172,127 @@ TELP \\\] yy_pop_state (); } <> { - LexerError ("EOF found inside a comment"); + LexerError (_ ("EOF found inside a comment").ch_C ()); if (! close_input ()) yyterminate (); // can't move this, since it actually rets a YY_NULL } } -\\maininput { - start_main_input (); +\\maininput { + if (!main_input_b_) + { + start_main_input (); + main_input_b_ = true; + } + else + error (_ ("\\maininput disallowed outside init files")); } -\\include { +\\include { yy_push_state (incl); } \"[^"]*\";? { /* got the include file name */ String s (YYText ()+1); s = s.left_str (s.index_last_i ('"')); - DOUT << "#include `" << s << "\'\n"; + new_input (s,source_global_l); yy_pop_state (); } +\\{BLACK}*;?{WHITE} { /* got the include identifier */ + String s = YYText () + 1; + strip_trailing_white (s); + if (s.length_i () && (s[s.length_i () - 1] == ';')) + s = s.left_str (s.length_i () - 1); + + SCM sid = lookup_identifier (s); + if (gh_string_p (sid)) { + new_input (ly_scm2string (sid), source_global_l); + yy_pop_state (); + } else { + String msg (_f ("wrong or undefined identifier: `%s'", s )); + + LexerError (msg.ch_C ()); + SCM err = scm_current_error_port (); + scm_puts ("This value was found in the table: ", err); + scm_display (sid, err); + } +} \"[^"]* { // backup rule - cerr << "missing end quote" << endl; + cerr << _ ("Missing end quote") << endl; exit (1); } -{RESTNAME} { +{RESTNAME} { const char *s = YYText (); - yylval.string = new String (s); - DOUT << "rest:"<< yylval.string; + yylval.scm = ly_str02scm (s); return RESTNAME; } -R { - return MEASURES; +R { + return MULTI_MEASURE_REST; } -\\\${BLACK}*{WHITE} { +\\\${BLACK}*{WHITE} { String s=YYText () + 2; s=s.left_str (s.length_i () - 1); - return scan_escaped_word (s); + return scan_escaped_word (s); } -\${BLACK}*{WHITE} { +\${BLACK}*{WHITE} { String s=YYText () + 1; s=s.left_str (s.length_i () - 1); return scan_bare_word (s); } -\\\${BLACK}* { // backup rule - cerr << "white expected" << endl; +\\\${BLACK}* { // backup rule + cerr << _ ("white expected") << endl; exit (1); } -\${BLACK}* { // backup rule - cerr << "white expected" << endl; +\${BLACK}* { // backup rule + cerr << _ ("white expected") << endl; exit (1); } -{ - {ALPHAWORD}/\' { - post_quotes_b_ = true; - return scan_bare_word (YYText ()); + +# { //embedded scm + //char const* s = YYText () + 1; + char const* s = here_ch_C (); + int n = 0; + if (main_input_b_ && safe_global_b) { + error (_ ("Can't evaluate Scheme in safe mode")); + yylval.scm = SCM_EOL; + return SCM_T; } - \'+ { - yylval.i = YYLeng (); - if (post_quotes_b_) { - post_quotes_b_ = false; - return POST_QUOTES; - } else - return PRE_QUOTES; + yylval.scm = ly_parse_scm (s, &n); + + for (int i=0; i < n; i++) + { + yyinput (); } + char_count_stack_.top () += n; + + return SCM_T; +} +{ + \> { + return FIGURE_CLOSE; + } + \< { + return FIGURE_OPEN; + } +} +{ {ALPHAWORD} { return scan_bare_word (YYText ()); - } {NOTECOMMAND} { - return scan_escaped_word (YYText ()+1); + return scan_escaped_word (YYText () + 1); + } + {FRACTION} { + yylval.scm = scan_fraction (YYText ()); + return FRACTION; } {DIGIT} { yylval.i = String_convert::dec2_i (String (YYText ())); return DIGIT; } - {UNSIGNED} { yylval.i = String_convert::dec2_i (String (YYText ())); return UNSIGNED; @@ -217,14 +308,19 @@ TELP \\\] } { \\{ESCAPED} { - *yylval.string += escaped_char(YYText()[1]); + *yylval.string += to_str (escaped_char (YYText ()[1])); } [^\\"]+ { *yylval.string += YYText (); } \" { - DOUT << "quoted string: `" << *yylval.string << "'\n"; + yy_pop_state (); + + /* yylval is union. Must remember STRING before setting SCM*/ + String *sp = yylval.string; + yylval.scm = ly_str02scm (sp->ch_C ()); + delete sp; return STRING; } . { @@ -233,56 +329,98 @@ TELP \\\] } { - \" { start_quote (); } + {FRACTION} { + yylval.scm = scan_fraction (YYText ()); + return FRACTION; + } {UNSIGNED} { yylval.i = String_convert::dec2_i (String (YYText ())); return UNSIGNED; } {NOTECOMMAND} { - return scan_escaped_word (YYText ()+1); + return scan_escaped_word (YYText () + 1); } {LYRICS} { /* ugr. This sux. */ String s (YYText ()); - int i = 0; - while ((i=s.index_i ("_")) != -1) // change word binding "_" to " " - *(s.ch_l () + i) = ' '; - if ((i=s.index_i ("\\,")) != -1) // change "\," to TeX's "\c " - { - *(s.ch_l () + i + 1) = 'c'; - s = s.left_str (i+2) + " " + s.right_str (s.length_i ()-i-2); - } - yylval.string = new String (s); - DOUT << "lyric : `" << s << "'\n"; + if (s == "__") + return yylval.i = EXTENDER; + if (s == "--") + return yylval.i = HYPHEN; + s = lyric_fudge (s); + + char c = s[s.length_i () - 1]; + if (c == '{' || c == '}') // brace open is for not confusing dumb tools. + here_input ().warning ( + _ ("Brace found at end of lyric. Did you forget a space?")); + yylval.scm = ly_str02scm (s.ch_C ()); + + return STRING; } . { - return yylval.c = YYText ()[0]; + return YYText ()[0]; + } +} +{ + {ALPHAWORD} { + return scan_bare_word (YYText ()); + } + {NOTECOMMAND} { + return scan_escaped_word (YYText () + 1); + } + {FRACTION} { + yylval.scm = scan_fraction (YYText ()); + return FRACTION; + } + {UNSIGNED} { + yylval.i = String_convert::dec2_i (String (YYText ())); + return UNSIGNED; + } + \" { + start_quote (); + } + - { + return CHORD_MINUS; + } + : { + return CHORD_COLON; + } + \/\+ { + return CHORD_BASS; + } + \^ { + return CHORD_CARET; + } + . { + return YYText ()[0]; } } <> { - DOUT << "<>"; + if (! close_input ()) { yyterminate (); // can't move this, since it actually rets a YY_NULL } } + + {WORD} { return scan_bare_word (YYText ()); } {KEYWORD} { - return scan_escaped_word (YYText ()+1); + return scan_escaped_word (YYText () + 1); } {REAL} { Real r; int cnv=sscanf (YYText (), "%lf", &r); assert (cnv == 1); - DOUT << "REAL" << r<<'\n'; - yylval.real = r; + + yylval.scm = gh_double2scm (r); return REAL; } @@ -293,30 +431,21 @@ TELP \\\] [{}] { - DOUT << "parens\n"; return YYText ()[0]; } [*:=] { char c = YYText ()[0]; - DOUT << "misc char" <{PLET} { - return yylval.i = PLET; -} -{TELP} { - return yylval.i = TELP; + return c; } -. { - return yylval.c = YYText ()[0]; +. { + return YYText ()[0]; } -\\. { +\\. { char c= YYText ()[1]; - yylval.c = c; + switch (c) { case '>': return E_BIGGER; @@ -324,13 +453,19 @@ TELP \\\] return E_SMALLER; case '!': return E_EXCLAMATION; + case '(': + return E_OPEN; + case ')': + return E_CLOSE; + case '~': + return E_TILDE; default: return E_CHAR; } } <*>. { - String msg= String ("illegal character: ") +String (YYText ()[0]); + String msg = _f ("invalid character: `%c'", YYText ()[0]); LexerError (msg.ch_C ()); return YYText ()[0]; } @@ -343,11 +478,23 @@ My_lily_lexer::push_note_state () yy_push_state (notes); } +void +My_lily_lexer::push_figuredbass_state() +{ + yy_push_state (figures); +} +void +My_lily_lexer::push_chord_state () +{ + yy_push_state (chords); +} + void My_lily_lexer::push_lyric_state () { yy_push_state (lyrics); } + void My_lily_lexer::pop_state () { @@ -356,51 +503,79 @@ My_lily_lexer::pop_state () int My_lily_lexer::scan_escaped_word (String str) -{ - DOUT << "\\word: `" << str<<"'\n"; +{ + // use more SCM for this. + + SCM sym = ly_symbol2scm (str.ch_C ()); + int l = lookup_keyword (str); if (l != -1) { - DOUT << "(keyword)\n"; return l; } - Identifier * id = lookup_identifier (str); - if (id) { - DOUT << "(identifier)\n"; - yylval.id = id; - return id->token_code_i_; - } - if (YYSTATE != notes) { - Melodic_req * mel_l = lookup_melodic_req_l (str); - if (mel_l) { - DOUT << "(notename)\n"; - yylval.melreq = mel_l; - mel_l->set_spot (Input (source_file_l (), here_ch_C ())); - return NOTENAME_ID; + SCM sid = lookup_identifier (str); + if (gh_string_p (sid)) { + yylval.scm = sid; + return STRING_IDENTIFIER; + } else if (gh_number_p (sid)) { + yylval.scm = sid; + return NUMBER_IDENTIFIER; + } else if (unsmob_translator_def (sid)) { + yylval.scm = sid; + return TRANSLATOR_IDENTIFIER; + } else if (unsmob_score (sid)) { + yylval.scm =sid; + return SCORE_IDENTIFIER; + } else if (Music * mus =unsmob_music (sid)) { + yylval.scm = sid; + + return dynamic_cast (mus) ? REQUEST_IDENTIFIER : MUSIC_IDENTIFIER; + } else if (unsmob_duration (sid)) { + yylval.scm = sid; + return DURATION_IDENTIFIER; + } else if (unsmob_music_output_def (sid)) { + yylval.scm = sid; + return MUSIC_OUTPUT_DEF_IDENTIFIER; + } + + if (sid != SCM_UNDEFINED) { + yylval.scm = sid; + return SCM_IDENTIFIER; + } + + if ((YYSTATE != notes) && (YYSTATE != chords)) { + SCM pitch = scm_hashq_get_handle (pitchname_tab_, sym); + + if (gh_pair_p (pitch)) + { + yylval.scm = ly_cdr (pitch); + return NOTENAME_PITCH; } } - String msg ("Unknown escaped string: `" + str + "'"); + String msg (_f ("unknown escaped string: `\\%s'", str)); LexerError (msg.ch_C ()); - DOUT << "(string)"; - String *sp = new String (str); - yylval.string=sp; + + yylval.scm = ly_str02scm (str.ch_C ()); + return STRING; } int My_lily_lexer::scan_bare_word (String str) { - DOUT << "word: `" << str<< "'\n"; - if (YYSTATE == notes){ - Melodic_req * mel_l = lookup_melodic_req_l (str); - if (mel_l) { - DOUT << "(notename)\n"; - yylval.melreq = mel_l; - mel_l->set_spot (Input (source_file_l (), here_ch_C ())); - return NOTENAME_ID; + SCM sym = ly_symbol2scm (str.ch_C ()); + if ((YYSTATE == notes) || (YYSTATE == chords)) { + SCM pitch = scm_hashq_get_handle (pitchname_tab_, sym); + if (gh_pair_p (pitch)) { + yylval.scm = ly_cdr (pitch); + return (YYSTATE == notes) ? NOTENAME_PITCH : TONICNAME_PITCH; + } else if ((pitch = scm_hashq_get_handle (chordmodifier_tab_, sym))!= SCM_BOOL_F) + { + yylval.scm = ly_cdr (pitch); + return CHORDMODIFIER_PITCH; } } - yylval.string=new String (str); + yylval.scm = ly_str02scm (str.ch_C ()); return STRING; } @@ -410,14 +585,30 @@ My_lily_lexer::note_state_b () const return YY_START == notes; } +bool +My_lily_lexer::chord_state_b () const +{ + return YY_START == chords; +} + bool My_lily_lexer::lyric_state_b () const { return YY_START == lyrics; } +bool +My_lily_lexer::figure_state_b () const +{ + return YY_START == figures; +} + +/* + urg, belong to String (_convert) + and should be generalised + */ void -strip_trailing_white (String&s) +strip_leading_white (String&s) { int i=0; for (; i < s.length_i (); i++) @@ -428,7 +619,7 @@ strip_trailing_white (String&s) } void -strip_leading_white (String&s) +strip_trailing_white (String&s) { int i=s.length_i (); while (i--) @@ -437,3 +628,71 @@ strip_leading_white (String&s) s = s.left_str (i+1); } + + + +Lilypond_version oldest_version ("1.3.59"); + +void +print_lilypond_versions (ostream &os) +{ + os << _f ("Oldest supported input version: %s", oldest_version.str ()) + << endl; +} + + +bool +valid_version_b (String s) +{ + Lilypond_version current ( MAJOR_VERSION "." MINOR_VERSION "." PATCH_LEVEL ); + Lilypond_version ver (s); + if (! ((ver >= oldest_version) && (ver <= current))) + { + non_fatal_error (_f ("incorrect lilypond version: %s (%s, %s)", ver.str (), oldest_version.str (), current.str ())); + non_fatal_error (_ ("Consider converting the input with the convert-ly script")); + return false; + } + return true; +} + + +String +lyric_fudge (String s) +{ + char * chars =s.copy_ch_p (); + + for (char * p = chars; *p ; p++) + { + if (*p == '_' && (p == chars || *(p-1) != '\\')) + *p = ' '; + } + + s = String (chars); + delete[] chars; + + int i =0; + if ((i=s.index_i ("\\,")) != -1) // change "\," to TeX's "\c " + { + * (s.ch_l () + i + 1) = 'c'; + s = s.left_str (i+2) + " " + s.right_str (s.length_i ()-i-2); + } + + return s; +} + +/* +Convert "NUM/DEN" into a '(NUM . DEN) cons. +*/ +SCM +scan_fraction (String frac) +{ + int i = frac.index_i ('/'); + int l = frac.length_i (); + String left = frac.left_str (i); + String right = frac.right_str (l - i - 1); + + int n = String_convert::dec2_i (left); + int d = String_convert::dec2_i (right); + return gh_cons (gh_int2scm (n), gh_int2scm (d)); +} +