@end ignore
+@item
+A number of shorthands like @code{(}, @code{)}, @code{|},
+@code{[}, @code{]}, @code{~}, @code{\(}, @code{\)} and others can
+now freely be redefined like normal commands. An example would be
+@lilypond[verbatim,quote]
+"\\{" = (
+"\\}" = )
+"(" = \melisma
+")" = \melismaEnd
+
+\new Staff <<
+ \relative c' {
+ c8 \{ d e f \} % slurred
+ g ( a b c ) % no slur, but with melisma
+ c,1 \bar "|."
+ }
+ \addlyrics { Li -- ly -- pond. }
+>>
+@end lilypond
+
@item
The articulation shorthand for @code{\staccatissimo} has been
renamed from @code{-|} to@tie{}@code{-!}.
int scan_bare_word (string);
SCM scan_markup_word (string);
int scan_escaped_word (string);
+ int scan_shorthand (string);
int scan_scm_id (SCM);
int identifier_type (SCM);
char escaped_char (char) const;
ANY_CHAR (.|\n)
WORD {A}([-_]{A}|{A})*
COMMAND \\{WORD}
-
+/* SPECIAL category is for every letter that needs to get passed to
+ * the parser rather than being redefinable by the user */
+SPECIAL [-+*/=<>{}!?_^'',.:]
+SHORTHAND (.|\\.)
UNSIGNED {N}+
E_UNSIGNED \\{N}+
FRACTION {N}+\/{N}+
yylval = SCM_UNSPECIFIED;
return FIGURE_OPEN;
}
+ \\\+ {
+ yylval = SCM_UNSPECIFIED;
+ return E_PLUS;
+ }
+ \\! {
+ yylval = SCM_UNSPECIFIED;
+ return E_EXCLAMATION;
+ }
+ \\\\ {
+ yylval = SCM_UNSPECIFIED;
+ return E_BACKSLASH;
+ }
+ [][] {
+ yylval = SCM_UNSPECIFIED;
+ return YYText ()[0];
+ }
}
<notes,figures>{
{COMMAND} {
return scan_escaped_word (YYText_utf8 () + 1);
}
- /* Characters needed to express durations, assignments, barchecks */
- [*.=|] {
+ \\.|\| {
+ // UTF-8 already covered by COMMAND
+ return scan_shorthand (YYText ());
+ }
+ /* Characters needed to express durations, assignments */
+ [*.=] {
yylval = SCM_UNSPECIFIED;
return YYText ()[0];
}
return STRING;
}
/* This should really just cover {} */
- . {
+ [{}] {
yylval = SCM_UNSPECIFIED;
- return YYText ()[0]; // above catches all multibytes.
+ return YYText ()[0];
}
}
<chords>{
yylval = SCM_UNSPECIFIED;
return CHORD_CARET;
}
- . {
- yylval = SCM_UNSPECIFIED;
- return YYText ()[0]; // WORD catches all multibyte.
- }
}
yylval = ly_string2scm (s);
return STRING;
}
- . {
+ [{}] {
yylval = SCM_UNSPECIFIED;
- return YYText ()[0]; // Above is catchall for multibyte
+ return YYText ()[0];
}
}
}
-[{}] {
- yylval = SCM_UNSPECIFIED;
- return YYText ()[0];
-}
-
--/\. | // backup rule
-[*:=] {
+-/\. { // backup rule
yylval = SCM_UNSPECIFIED;
return YYText ()[0];
}
-<INITIAL,notes,figures>. {
+<INITIAL,chords,lyrics,figures,notes>{SPECIAL} {
yylval = SCM_UNSPECIFIED;
return YYText ()[0];
}
-<INITIAL,lyrics,notes,figures>\\. {
- yylval = SCM_UNSPECIFIED;
- char c = YYText ()[1];
-
- switch (c) {
- case '>':
- return E_ANGLE_CLOSE;
- case '<':
- return E_ANGLE_OPEN;
- case '!':
- return E_EXCLAMATION;
- case '(':
- return E_OPEN;
- case ')':
- return E_CLOSE;
- case '[':
- return E_BRACKET_OPEN;
- case '+':
- return E_PLUS;
- case ']':
- return E_BRACKET_CLOSE;
- case '~':
- return E_TILDE;
- case '\\':
- return E_BACKSLASH;
-
- default:
- return E_CHAR;
- }
+<INITIAL,chords,lyrics,figures,notes>{SHORTHAND} {
+ return scan_shorthand (YYText_utf8 ()); // should not be utf-8
}
<*>.[\200-\277]* {
return STRING;
}
+int
+Lily_lexer::scan_shorthand (string str)
+{
+ SCM sid = lookup_identifier (str);
+ if (Music *m = unsmob_music (sid))
+ {
+ m->set_spot (override_input (last_input_));
+ }
+
+ if (sid != SCM_UNDEFINED)
+ return scan_scm_id (sid);
+
+ string msg (_f ("undefined character or shorthand: %s", str));
+ LexerError (msg.c_str ());
+
+ yylval = ly_string2scm (str);
+
+ return STRING;
+}
+
int
Lily_lexer::scan_scm_id (SCM sid)
{
%token DOUBLE_ANGLE_OPEN "<<"
%token DOUBLE_ANGLE_CLOSE ">>"
%token E_BACKSLASH "\\"
-%token E_ANGLE_CLOSE "\\>"
-%token E_CHAR "\\C[haracter]"
-%token E_CLOSE "\\)"
%token E_EXCLAMATION "\\!"
-%token E_BRACKET_OPEN "\\["
-%token E_OPEN "\\("
-%token E_BRACKET_CLOSE "\\]"
-%token E_ANGLE_OPEN "\\<"
%token E_PLUS "\\+"
-%token E_TILDE "\\~"
%token EXTENDER "__"
/*
command_event {
$$ = $1;
}
- | E_BRACKET_OPEN {
- Music *m = MY_MAKE_MUSIC ("LigatureEvent", @$);
- m->set_property ("span-direction", scm_from_int (START));
- $$ = m->unprotect();
- }
- | E_BRACKET_CLOSE {
- Music *m = MY_MAKE_MUSIC ("LigatureEvent", @$);
- m->set_property ("span-direction", scm_from_int (STOP));
- $$ = m->unprotect ();
- }
- | E_BACKSLASH {
- $$ = MAKE_SYNTAX ("voice-separator", @$);
- }
- | '|' {
- SCM pipe = parser->lexer_->lookup_identifier ("pipeSymbol");
-
- Music *m = unsmob_music (pipe);
- if (m)
- {
- m = m->clone ();
- m->set_spot (@$);
- $$ = m->unprotect ();
- }
- else
- $$ = MAKE_SYNTAX ("bar-check", @$);
-
- }
;
command_event:
- E_TILDE {
- $$ = MY_MAKE_MUSIC ("PesOrFlexaEvent", @$)->unprotect ();
- }
- | tempo_event {
+ tempo_event {
$$ = $1;
}
;
}
;
-direction_less_char:
- '[' {
- $$ = ly_symbol2scm ("bracketOpenSymbol");
- }
- | ']' {
- $$ = ly_symbol2scm ("bracketCloseSymbol");
- }
- | '~' {
- $$ = ly_symbol2scm ("tildeSymbol");
- }
- | '(' {
- $$ = ly_symbol2scm ("parenthesisOpenSymbol");
- }
- | ')' {
- $$ = ly_symbol2scm ("parenthesisCloseSymbol");
- }
- | E_EXCLAMATION {
- $$ = ly_symbol2scm ("escapedExclamationSymbol");
- }
- | E_OPEN {
- $$ = ly_symbol2scm ("escapedParenthesisOpenSymbol");
- }
- | E_CLOSE {
- $$ = ly_symbol2scm ("escapedParenthesisCloseSymbol");
- }
- | E_ANGLE_CLOSE {
- $$ = ly_symbol2scm ("escapedBiggerSymbol");
- }
- | E_ANGLE_OPEN {
- $$ = ly_symbol2scm ("escapedSmallerSymbol");
- }
- ;
-
direction_less_event:
- direction_less_char {
- SCM predefd = parser->lexer_->lookup_identifier_symbol ($1);
- Music *m = 0;
- if (unsmob_music (predefd))
- {
- m = unsmob_music (predefd)->clone ();
- m->set_spot (@$);
- }
- else
- {
- m = MY_MAKE_MUSIC ("Music", @$);
- }
- $$ = m->unprotect ();
- }
- | string_number_event
+ string_number_event
| EVENT_IDENTIFIER {
$$ = $1;
}
}
| bass_figure figured_bass_modification {
Music *m = unsmob_music ($1);
- if ($2 == ly_symbol2scm ("plus"))
- {
- m->set_property ("augmented", SCM_BOOL_T);
- }
- else if ($2 == ly_symbol2scm ("slash"))
- {
- m->set_property ("diminished", SCM_BOOL_T);
- }
- else if ($2 == ly_symbol2scm ("exclamation"))
- {
- m->set_property ("no-continuation", SCM_BOOL_T);
- }
- else if ($2 == ly_symbol2scm ("backslash"))
- {
- m->set_property ("augmented-slash", SCM_BOOL_T);
- }
+ m->set_property ($2, SCM_BOOL_T);
}
;
figured_bass_modification:
E_PLUS {
- $$ = ly_symbol2scm ("plus");
+ $$ = ly_symbol2scm ("augmented");
}
| E_EXCLAMATION {
- $$ = ly_symbol2scm ("exclamation");
+ $$ = ly_symbol2scm ("no-continuation");
}
| '/' {
- $$ = ly_symbol2scm ("slash");
+ $$ = ly_symbol2scm ("diminished");
}
| E_BACKSLASH {
- $$ = ly_symbol2scm ("backslash");
+ $$ = ly_symbol2scm ("augmented-slash");
}
;
escapedParenthesisCloseSymbol = #(make-span-event 'PhrasingSlurEvent STOP)
escapedBiggerSymbol = #(make-span-event 'DecrescendoEvent START)
escapedSmallerSymbol = #(make-span-event 'CrescendoEvent START)
+"\\[" = #(make-span-event 'LigatureEvent START)
+"\\]" = #(make-span-event 'LigatureEvent STOP)
+"\\~" = #(make-music 'PesOrFlexaEvent)
+"\\\\" = #(make-music 'VoiceSeparator)
\include "scale-definitions-init.ly"
return str
@rule((2, 17, 25), r'''\tempo 4. = 50~60 -> \tempo 4. = 50-60
--| -> -!''')
+-| -> -!
+pipeSymbol, escapedParenthesisOpenSymbol ... -> "|", "\\(" ...''')
def conv(str):
# This goes for \tempo commands ending with a range, like
# = 50 ~ 60
return m.group (0)
str = re.sub (r"([-^_])\||" + matchstring + r"|[-^_][-^_]", subnonstring, str)
str = re.sub (r"\bdashBar\b", "dashBang", str)
+ orig = [ "pipeSymbol",
+ "bracketOpenSymbol",
+ "bracketCloseSymbol",
+ "tildeSymbol",
+ "parenthesisOpenSymbol",
+ "parenthesisCloseSymbol",
+ "escapedExclamationSymbol",
+ "escapedParenthesisOpenSymbol",
+ "escapedParenthesisCloseSymbol",
+ "escapedBiggerSymbol",
+ "escapedSmallerSymbol" ]
+ repl = [ r'"|"',
+ r'"["',
+ r'"]"',
+ r'"~"',
+ r'"("',
+ r'")"',
+ r'"\\!"',
+ r'"\\("',
+ r'"\\)"',
+ r'"\\>"',
+ r'"\\<"']
+ words = r"\b(?:(" + ")|(".join (orig) + r"))\b"
+ def wordreplace(m):
+ def instring(m):
+ return re.sub (r'["\\]',r'\\\g<0>',repl[m.lastindex-1])
+ if m.lastindex:
+ return repl[m.lastindex-1]
+ return '"' + re.sub (words, instring, m.group(0)[1:-1]) + '"'
+ str = re.sub (words + "|" + matchstring, wordreplace, str)
return str
# Guidelines to write rules (please keep this at the end of this file)
'change-to-type type
'change-to-id id))
-(define-ly-syntax-simple (voice-separator)
- (make-music 'VoiceSeparator))
-
-(define-ly-syntax-simple (bar-check)
- (make-music 'BarCheck))
-
(define-ly-syntax (tempo parser location text . rest)
(let* ((unit (and (pair? rest)
(car rest)))