A [a-zA-Z\200-\377]
AA {A}|_
N [0-9]
-AN {AA}|{N}
ANY_CHAR (.|\n)
PUNCT [][()?!:'`]
SPECIAL_CHAR [&@]
NATIONAL [\001-\006\021-\027\031\036]
TEX {AA}|-|{PUNCT}|{NATIONAL}|{SPECIAL_CHAR}
-DASHED_WORD {A}({AN}|-)*
-DASHED_KEY_WORD \\{DASHED_WORD}
+WORD {A}([-_]{A}|{A})*
+COMMAND \\{WORD}
-
-
-ALPHAWORD {A}+
UNSIGNED {N}+
E_UNSIGNED \\{N}+
FRACTION {N}+\/{N}+
HORIZONTALWHITE [ \t]
BLACK [^ \n\t\f\r]
RESTNAME [rs]
-NOTECOMMAND \\{A}+
-MARKUPCOMMAND \\({A}|[-_])+
LYRICS ({AA}|{TEX})[^0-9 \t\n\r\f]*
ESCAPED [nt\\'"]
EXTENDER __
}
-<sourcefilename>\"[^"]*\" {
+<sourcefilename>\"[^""]*\" {
string s (YYText_utf8 () + 1);
s = s.substr (0, s.rfind ('\"'));
error (_ ("end quote missing"));
exit (1);
}
+
+ /* Flex picks the longest matching pattern including trailing
+ * contexts. Without the backup pattern, r-. does not trigger the
+ * {RESTNAME} rule but rather the {WORD}/[-_] rule coming later,
+ * needed for avoiding backup states.
+ */
+
+<chords,notes,figures>{RESTNAME}/[-_] | // pseudo backup rule
<chords,notes,figures>{RESTNAME} {
char const *s = YYText ();
yylval.scm = scm_from_locale_string (s);
return RESTNAME;
}
+<chords,notes,figures>q/[-_] | // pseudo backup rule
<chords,notes,figures>q {
return CHORD_REPETITION;
}
+<chords,notes,figures>R/[-_] | // pseudo backup rule
<chords,notes,figures>R {
return MULTI_MEASURE_REST;
}
}
char_count_stack_.back () += n;
- sval = eval_scm (sval);
-
+ sval = eval_scm (sval, '$');
+
int token = scan_scm_id (sval);
if (!scm_is_eq (yylval.scm, SCM_UNSPECIFIED))
- return token;
+ return token;
}
<INITIAL,notes,lyrics>{
}
<notes,figures>{
- {ALPHAWORD} {
+ {WORD}/[-_] | // backup rule
+ {WORD} {
return scan_bare_word (YYText_utf8 ());
}
- {NOTECOMMAND} {
+ {COMMAND}/[-_] | // backup rule
+ {COMMAND} {
return scan_escaped_word (YYText_utf8 () + 1);
}
{FRACTION} {
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.scm = scm_c_read_string (YYText ());
return UNSIGNED;
}
- {NOTECOMMAND} {
+ {COMMAND}/[-_] | // backup rule
+ {COMMAND} {
return scan_escaped_word (YYText_utf8 () + 1);
}
{LYRICS} {
}
}
<chords>{
- {ALPHAWORD} {
+ {WORD}/[-_] | // backup rule
+ {WORD} {
return scan_bare_word (YYText_utf8 ());
}
- {NOTECOMMAND} {
+ {COMMAND}/[-_] | // backup rule
+ {COMMAND} {
return scan_escaped_word (YYText_utf8 () + 1);
}
{FRACTION} {
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.scm = scm_c_read_string (YYText ());
return CHORD_CARET;
}
. {
- return YYText ()[0]; // ALPHAWORD catches all multibyte.
+ return YYText ()[0]; // WORD catches all multibyte.
}
}
\\score {
return SCORE;
}
- {MARKUPCOMMAND} {
+ {COMMAND}/[-_] | // backup rule
+ {COMMAND} {
string str (YYText_utf8 () + 1);
int token_type = MARKUP_FUNCTION;
reflect after.
*/
is_main_input_ = include_stack_.size () > 2;
- if (!close_input ())
+ if (!close_input () || !is_main_input_)
/* Returns YY_NULL */
yyterminate ();
}
}
<INITIAL>{
- {DASHED_WORD} {
+ {WORD}/[-_] | // backup rule
+ {WORD} {
return scan_bare_word (YYText_utf8 ());
}
- {DASHED_KEY_WORD} {
+ {COMMAND}/[-_] | // backup rule
+ {COMMAND} {
return scan_escaped_word (YYText_utf8 () + 1);
}
}
yylval.scm = scm_c_read_string (YYText ());
return REAL;
}
--\. { // backup rule
- yylval.scm = scm_from_double (0.0);
- return REAL;
-}
{UNSIGNED}/\/ | // backup rule
{UNSIGNED} {
return YYText ()[0];
}
+
+-/\. | // backup rule
[*:=] {
char c = YYText ()[0];
}
void
-Lily_lexer::push_chord_state (SCM tab)
+Lily_lexer::push_chord_state (SCM alist)
{
- pitchname_tab_stack_ = scm_cons (tab, pitchname_tab_stack_);
+ SCM p = scm_assq (alist, pitchname_tab_stack_);
+
+ if (scm_is_false (p))
+ p = scm_cons (alist, alist_to_hashq (alist));
+ pitchname_tab_stack_ = scm_cons (p, pitchname_tab_stack_);
yy_push_state (chords);
}
}
void
-Lily_lexer::push_note_state (SCM tab)
+Lily_lexer::push_note_state (SCM alist)
{
- pitchname_tab_stack_ = scm_cons (tab, pitchname_tab_stack_);
+ bool extra = (YYSTATE == extratoken);
+
+ SCM p = scm_assq (alist, pitchname_tab_stack_);
+
+ if (extra)
+ yy_pop_state ();
+
+ if (scm_is_false (p))
+ p = scm_cons (alist, alist_to_hashq (alist));
+ pitchname_tab_stack_ = scm_cons (p, pitchname_tab_stack_);
yy_push_state (notes);
+
+ if (extra) {
+ hidden_state_ = YYSTATE;
+ yy_push_state (extratoken);
+ }
}
void
if ((YYSTATE == notes) || (YYSTATE == chords)) {
SCM handle = SCM_BOOL_F;
if (scm_is_pair (pitchname_tab_stack_))
- handle = scm_hashq_get_handle (scm_car (pitchname_tab_stack_), sym);
+ handle = scm_hashq_get_handle (scm_cdar (pitchname_tab_stack_), sym);
if (scm_is_pair (handle)) {
yylval.scm = scm_cdr (handle);
return get_state () == figures;
}
+// The extra_token parameter specifies how to convert multiple values
+// into additional tokens. For '#', additional values get pushed as
+// SCM_IDENTIFIER. For '$', they get checked for their type and get
+// pushed as a corresponding *_IDENTIFIER token. Since the latter
+// tampers with yylval, it can only be done from the lexer itself, so
+// this function is private.
+
SCM
-Lily_lexer::eval_scm (SCM readerdata)
+Lily_lexer::eval_scm (SCM readerdata, char extra_token)
{
SCM sval = SCM_UNDEFINED;
error_level_ = 1;
return SCM_UNSPECIFIED;
}
+
+ if (extra_token && SCM_VALUESP (sval))
+ {
+ sval = scm_struct_ref (sval, SCM_INUM0);
+
+ if (scm_is_pair (sval)) {
+ for (SCM v = scm_reverse (scm_cdr (sval));
+ scm_is_pair (v);
+ v = scm_cdr (v))
+ {
+ int token;
+ switch (extra_token) {
+ case '$':
+ token = scan_scm_id (scm_car (v));
+ if (!scm_is_eq (yylval.scm, SCM_UNSPECIFIED))
+ push_extra_token (token, yylval.scm);
+ break;
+ case '#':
+ push_extra_token (SCM_IDENTIFIER, scm_car (v));
+ break;
+ }
+ }
+ sval = scm_car (sval);
+ } else
+ sval = SCM_UNSPECIFIED;
+ }
+
return sval;
}