-%{ // -*-Fundamental-*-
+%{ // -*- mode: c++; c-file-style: "linux" -*-
/*
This file is part of LilyPond, the GNU music typesetter.
along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
+/* Mode and indentation are at best a rough approximation based on TAB
+ * formatting (reasonable for compatibility with unspecific editor
+ * modes as Flex modes are hard to find) and need manual correction
+ * frequently. Without a reasonably dependable way of formatting a
+ * Flex file sensibly, there is little point in trying to fix the
+ * inconsistent state of indentation.
+ */
+
/*
backup rules
using namespace std;
#include "context-def.hh"
-#include "identifier-smob.hh"
+#include "duration.hh"
#include "international.hh"
#include "interval.hh"
#include "lily-guile.hh"
#include "music-function.hh"
#include "parse-scm.hh"
#include "parser.hh"
+#include "pitch.hh"
#include "source-file.hh"
#include "std-string.hh"
#include "string-convert.hh"
yy_push_state (lyric_quote);\
yylval.string = new string
-#define yylval \
- (*(YYSTYPE*)lexval_)
+#define yylval (*lexval_)
-#define yylloc \
- (*(YYLTYPE*)lexloc_)
+#define yylloc (*lexloc_)
#define YY_USER_ACTION add_lexed_char (YYLeng ());
ANY_CHAR (.|\n)
PUNCT [?!:'`]
ACCENT \\[`'"^]
+SPECIAL_CHAR [&@]
NATIONAL [\001-\006\021-\027\031\036]
-TEX {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}
-WORD {A}{AN}*
+TEX {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}|{SPECIAL_CHAR}
DASHED_WORD {A}({AN}|-)*
DASHED_KEY_WORD \\{DASHED_WORD}
ALPHAWORD {A}+
-DIGIT {N}
UNSIGNED {N}+
E_UNSIGNED \\{N}+
FRACTION {N}+\/{N}+
INT -?{UNSIGNED}
REAL ({INT}\.{N}*)|(-?\.{N}+)
-KEYWORD \\{WORD}
WHITE [ \n\t\f\r]
HORIZONTALWHITE [ \t]
BLACK [^ \n\t\f\r]
<*>\r {
- // windows-suck-suck-suck
+ // swallow and ignore carriage returns
}
<extratoken>{ANY_CHAR} {
yyless (0);
/* produce requested token */
- int type = extra_token_types_.back ();
- extra_token_types_.pop_back ();
- if (extra_token_types_.empty ())
+ int type = scm_to_int (scm_caar (extra_tokens_));
+ yylval.scm = scm_cdar (extra_tokens_);
+ extra_tokens_ = scm_cdr (extra_tokens_);
+ if (scm_is_null (extra_tokens_))
+ yy_pop_state ();
+
+ return type;
+}
+
+<extratoken><<EOF>> {
+ /* Generate a token without swallowing anything */
+
+ /* produce requested token */
+ int type = scm_to_int (scm_caar (extra_tokens_));
+ yylval.scm = scm_cdar (extra_tokens_);
+ extra_tokens_ = scm_cdr (extra_tokens_);
+ if (scm_is_null (extra_tokens_))
yy_pop_state ();
return type;
<INITIAL,chords,lyrics,figures,notes>{BOM_UTF8}/.* {
if (this->lexloc_->line_number () != 1 || this->lexloc_->column_number () != 0)
{
- LexerError (_ ("stray UTF-8 BOM encountered").c_str ());
- exit (1);
+ LexerWarning (_ ("stray UTF-8 BOM encountered").c_str ());
+ // exit (1);
}
- if (be_verbose_global)
- message (_ ("Skipping UTF-8 BOM"));
+ debug_output (_ ("Skipping UTF-8 BOM"));
}
<INITIAL,chords,figures,incl,lyrics,markup,notes>{
"%{" {
yy_push_state (longcomment);
}
- %[^{\n\r].*[\n\r] {
+ %[^{\n\r][^\n\r]*[\n\r] {
}
%[^{\n\r] { // backup rule
}
%[\n\r] {
}
- %[^{\n\r].* {
+ %[^{\n\r][^\n\r]* {
}
{WHITE}+ {
this->here_input ().get_source_file ()->set_line (here_input ().start (), i);
}
-<version>. {
+<version>{ANY_CHAR} {
LexerError (_ ("quoted string expected after \\version").c_str ());
yy_pop_state ();
}
-<sourcefilename>. {
+<sourcefilename>{ANY_CHAR} {
LexerError (_ ("quoted string expected after \\sourcefilename").c_str ());
yy_pop_state ();
}
-<sourcefileline>. {
+<sourcefileline>{ANY_CHAR} {
LexerError (_ ("integer expected after \\sourcefileline").c_str ());
yy_pop_state ();
}
"%"+"}" {
yy_pop_state ();
}
- <<EOF>> {
- LexerError (_ ("EOF found inside a comment").c_str ());
- is_main_input_ = false; // should be safe , can't have \include in --safe.
- if (! close_input ())
- yyterminate (); // can't move this, since it actually rets a YY_NULL
- }
}
<INITIAL,chords,lyrics,figures,notes>\\include {
yy_push_state (incl);
}
-<incl>\"[^"]*\" { /* got the include file name */
+<incl>\"[^""]*\" { /* got the include file name */
string s (YYText ()+1);
s = s.substr (0, s.rfind ('"'));
new_input (s, sources_);
yy_pop_state ();
}
-<incl>\\{BLACK}*{WHITE} { /* got the include identifier */
+<incl>\\{BLACK}*{WHITE}? { /* got the include identifier */
string s = YYText () + 1;
strip_trailing_white (s);
if (s.length () && (s[s.length () - 1] == ';'))
if (scm_is_string (sid)) {
new_input (ly_scm2string (sid), sources_);
yy_pop_state ();
- } else {
+ } else {
string msg (_f ("wrong or undefined identifier: `%s'", s ));
LexerError (msg.c_str ());
scm_display (sid, err);
}
}
-<incl>\"[^"]* { // backup rule
+<incl>(\$|#) { // scm for the filename
+ int n = 0;
+ Input hi = here_input();
+ hi.step_forward ();
+ SCM sval = ly_parse_scm (hi.start (), &n, hi,
+ be_safe_global && is_main_input_, parser_);
+ sval = eval_scm (sval);
+
+ for (int i = 0; i < n; i++)
+ {
+ yyinput ();
+ }
+ char_count_stack_.back () += n;
+
+ if (scm_is_string (sval)) {
+ new_input (ly_scm2string (sval), sources_);
+ yy_pop_state ();
+ } else {
+ LexerError (_ ("string expected after \\include").c_str ());
+ if (sval != SCM_UNDEFINED) {
+ SCM err = scm_current_error_port ();
+ scm_puts ("This value was found instead: ", err);
+ scm_display (sval, err);
+ }
+ }
+}
+
+<incl,version,sourcefilename>\"[^""]* { // backup rule
error (_ ("end quote missing"));
exit (1);
}
be_safe_global && is_main_input_, parser_);
if (sval == SCM_UNDEFINED)
- {
- sval = SCM_UNSPECIFIED;
error_level_ = 1;
- }
for (int i = 0; i < n; i++)
{
}
char_count_stack_.back () += n;
- if (unpack_identifier (sval) != SCM_UNDEFINED)
+ yylval.scm = sval;
+ return SCM_TOKEN;
+}
+
+<INITIAL,chords,figures,lyrics,markup,notes>\$ { //immediate scm
+ int n = 0;
+ Input hi = here_input();
+ hi.step_forward ();
+ SCM sval = ly_parse_scm (hi.start (), &n, hi,
+ be_safe_global && is_main_input_, parser_);
+
+ for (int i = 0; i < n; i++)
{
- yylval.scm = unpack_identifier(sval);
- return identifier_type (yylval.scm);
+ yyinput ();
}
+ char_count_stack_.back () += n;
- for (size_t i = 0; i < pending_string_includes_.size (); i++)
- new_input ("<included string>", pending_string_includes_[i],
- parser_->sources_);
- pending_string_includes_.clear ();
+ sval = eval_scm (sval);
- yylval.scm = sval;
- return SCM_TOKEN;
+ int token = scan_scm_id (sval);
+ if (!scm_is_eq (yylval.scm, SCM_UNSPECIFIED))
+ return token;
}
+
<INITIAL,notes,lyrics>{
\<\< {
return DOUBLE_ANGLE_OPEN;
yylval.scm = scan_fraction (YYText ());
return FRACTION;
}
-
- {DIGIT} {
- yylval.i = String_convert::dec2int (string (YYText ()));
- return DIGIT;
- }
+ {UNSIGNED}/\/ | // backup rule
{UNSIGNED} {
- yylval.i = String_convert::dec2int (string (YYText ()));
+ yylval.scm = scm_c_read_string (YYText ());
return UNSIGNED;
}
{E_UNSIGNED} {
yylval.scm = scan_fraction (YYText ());
return FRACTION;
}
+ {UNSIGNED}/\/[^0-9] { // backup rule
+ yylval.scm = scm_c_read_string (YYText ());
+ return UNSIGNED;
+ }
+ {UNSIGNED}/\/ | // backup rule
{UNSIGNED} {
- yylval.i = String_convert::dec2int (string (YYText ()));
+ yylval.scm = scm_c_read_string (YYText ());
return UNSIGNED;
}
{NOTECOMMAND} {
yylval.scm = scan_fraction (YYText ());
return FRACTION;
}
+ {UNSIGNED}/\/[^0-9] { // backup rule
+ yylval.scm = scm_c_read_string (YYText ());
+ return UNSIGNED;
+ }
+ {UNSIGNED}/\/ | // backup rule
{UNSIGNED} {
- yylval.i = String_convert::dec2int (string (YYText ()));
+ yylval.scm = scm_c_read_string (YYText ());
return UNSIGNED;
}
- {
else if (predicate == ly_lily_module_constant ("markup?"))
push_extra_token(EXPECT_MARKUP);
else
- push_extra_token(EXPECT_SCM);
+ push_extra_token(EXPECT_SCM, predicate);
}
return token_type;
}
[{}] {
return YYText ()[0];
}
- [^#{}"\\ \t\n\r\f]+ {
+ [^$#{}\"\\ \t\n\r\f]+ {
string s (YYText ());
char c = s[s.length () - 1];
}
}
-<*><<EOF>> {
- if (is_main_input_)
+<longcomment><<EOF>> {
+ LexerError (_ ("EOF found inside a comment").c_str ());
+ is_main_input_ = false; // should be safe , can't have \include in --safe.
+ if (!close_input ())
+ yyterminate (); // can't move this, since it actually rets a YY_NULL
+ }
+
+<<EOF>> { if (is_main_input_)
{
/* 2 = init.ly + current file.
> because we're before closing, but is_main_input_ should
}
}
-{WORD} {
- return scan_bare_word (YYText ());
-}
-{KEYWORD} {
- return scan_escaped_word (YYText () + 1);
-}
+-{UNSIGNED} | // backup rule
{REAL} {
- Real r;
- int cnv = sscanf (YYText (), "%lf", &r);
- assert (cnv == 1);
- (void) cnv;
-
- yylval.scm = scm_from_double (r);
+ yylval.scm = scm_c_read_string (YYText ());
+ return REAL;
+}
+-\. { // backup rule
+ yylval.scm = scm_from_double (0.0);
return REAL;
}
{UNSIGNED} {
- yylval.i = String_convert::dec2int (string (YYText ()));
+ yylval.scm = scm_c_read_string (YYText ());
return UNSIGNED;
}
/* Make the lexer generate a token of the given type as the next token.
TODO: make it possible to define a value for the token as well */
void
-Lily_lexer::push_extra_token (int token_type)
+Lily_lexer::push_extra_token (int token_type, SCM scm)
{
- if (extra_token_types_.empty ())
+ if (scm_is_null (extra_tokens_))
{
if (YY_START != extratoken)
hidden_state_ = YY_START;
yy_push_state (extratoken);
}
- extra_token_types_.push_back (token_type);
+ extra_tokens_ = scm_acons (scm_from_int (token_type), scm, extra_tokens_);
}
void
return i;
SCM sid = lookup_identifier (str);
+ if (sid != SCM_UNDEFINED)
+ return scan_scm_id (sid);
+
+ string msg (_f ("unknown escaped string: `\\%s'", str));
+ LexerError (msg.c_str ());
+
+ yylval.scm = ly_string2scm (str);
+
+ return STRING;
+}
+
+int
+Lily_lexer::scan_scm_id (SCM sid)
+{
if (is_music_function (sid))
{
+ int funtype = SCM_FUNCTION;
+
yylval.scm = get_music_function_transform (sid);
SCM s = scm_object_property (yylval.scm, ly_symbol2scm ("music-function-signature"));
- push_extra_token (EXPECT_NO_MORE_ARGS);
- for (; scm_is_pair (s); s = scm_cdr (s))
+ SCM cs = scm_car (s);
+
+ if (scm_is_pair (cs))
{
- if (scm_car (s) == ly_music_p_proc)
- push_extra_token (EXPECT_MUSIC);
- else if (scm_car (s) == ly_lily_module_constant ("markup?"))
- push_extra_token (EXPECT_MARKUP);
- else if (ly_is_procedure (scm_car (s)))
- push_extra_token (EXPECT_SCM);
- else programming_error ("Function parameter without type-checking predicate");
+ cs = SCM_CAR (cs);
}
- return MUSIC_FUNCTION;
- }
- if (sid != SCM_UNDEFINED)
- {
- yylval.scm = sid;
- return identifier_type (sid);
- }
-
- string msg (_f ("unknown escaped string: `\\%s'", str));
- LexerError (msg.c_str ());
+ if (scm_is_eq (cs, ly_lily_module_constant ("ly:music?")))
+ funtype = MUSIC_FUNCTION;
+ else if (scm_is_eq (cs, ly_lily_module_constant ("ly:event?")))
+ funtype = EVENT_FUNCTION;
+ else if (ly_is_procedure (cs))
+ funtype = SCM_FUNCTION;
+ else programming_error ("Bad syntax function predicate");
- yylval.scm = ly_string2scm (str);
-
- return STRING;
+ push_extra_token (EXPECT_NO_MORE_ARGS);
+ for (s = scm_cdr (s); scm_is_pair (s); s = scm_cdr (s))
+ {
+ SCM optional = SCM_UNDEFINED;
+ cs = scm_car (s);
+
+ if (scm_is_pair (cs))
+ {
+ optional = SCM_CDR (cs);
+ cs = SCM_CAR (cs);
+ }
+
+ if (cs == Pitch_type_p_proc)
+ push_extra_token (EXPECT_PITCH);
+ else if (cs == Duration_type_p_proc)
+ push_extra_token (EXPECT_DURATION);
+ else if (ly_is_procedure (cs))
+ push_extra_token (EXPECT_SCM, cs);
+ else
+ {
+ programming_error ("Function parameter without type-checking predicate");
+ continue;
+ }
+ if (!scm_is_eq (optional, SCM_UNDEFINED))
+ push_extra_token (EXPECT_OPTIONAL, optional);
+ }
+ return funtype;
+ }
+ yylval.scm = sid;
+ return identifier_type (sid);
}
int
return get_state () == figures;
}
+SCM
+Lily_lexer::eval_scm (SCM readerdata)
+{
+ SCM sval = SCM_UNDEFINED;
+
+ if (!SCM_UNBNDP (readerdata))
+ {
+ sval = ly_eval_scm (scm_car (readerdata),
+ *unsmob_input (scm_cdr (readerdata)),
+ be_safe_global && is_main_input_,
+ parser_);
+ }
+
+ if (SCM_UNBNDP (sval))
+ {
+ error_level_ = 1;
+ return SCM_UNSPECIFIED;
+ }
+ return sval;
+}
+
+
+
/*
urg, belong to string (_convert)
and should be generalised
/*
- substitute _ and \,
+ substitute _
*/
string
lyric_fudge (string s)
{
- char *chars = string_copy (s);
-
- for (char *p = chars; *p ; p++)
- {
- if (*p == '_' && (p == chars || *(p-1) != '\\'))
- *p = ' ';
- }
-
- s = string (chars);
- delete[] chars;
+ size_t i=0;
- ssize i = 0;
- if ((i = s.find ("\\,")) != NPOS) // change "\," to TeX's "\c "
- {
- * (((char*)s.c_str ()) + i + 1) = 'c';
- s = s.substr (0, i + 2) + " " + s.substr (i - 2);
- }
-
- return s;
+ while ((i = s.find ('_', i)) != string::npos)
+ {
+ s[i++] = ' ';
+ }
+ return s;
}
/*