-%{ // -*-Fundamental-*-
+%{ // -*- mode: c++; c-file-style: "linux" -*-
/*
This file is part of LilyPond, the GNU music typesetter.
- Copyright (C) 1996--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ Copyright (C) 1996--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
Jan Nieuwenhuizen <janneke@gnu.org>
LilyPond is free software: you can redistribute it and/or modify
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
bool is_valid_version (string s);
-#define start_quote() \
- yy_push_state (quote);\
- yylval.string = new string
+#define start_quote() do { \
+ yy_push_state (quote); \
+ yylval = SCM_EOL; \
+ } while (0)
-#define start_lyric_quote() \
- yy_push_state (lyric_quote);\
- yylval.string = new string
+#define start_lyric_quote() do { \
+ yy_push_state (lyric_quote); \
+ yylval = SCM_EOL; \
+ } while (0)
-#define yylval \
- (*(YYSTYPE*)lexval_)
+#define yylval (*lexval_)
-#define yylloc \
- (*(YYLTYPE*)lexloc_)
+#define yylloc (*lexloc_)
#define YY_USER_ACTION add_lexed_char (YYLeng ());
%x sourcefilename
%x version
+/* The strategy concerning multibyte characters is to accept them but
+ * call YYText_utf8 for patterns that might contain them, in order to
+ * get a single code path responsible for flagging non-UTF-8 input:
+ * Patterns for accepting only valid UTF-8 without backing up are
+ * really hard to do and complex, and if nice error messages are
+ * wanted, one would need patterns catching the invalid input as well.
+ *
+ * Since editors and operating environments don't necessarily behave
+ * reasonably in the presence of mixed encodings, we flag encoding
+ * errors also in identifiers, comments, and strings where it would be
+ * conceivable to just transparently work with the byte string. But
+ * the whole point of caring about UTF-8 in here at all is too avoid
+ * stranger errors later when input passes into backends or log files
+ * or console output or error messages.
+ */
+
A [a-zA-Z\200-\377]
AA {A}|_
N [0-9]
-AN {AA}|{N}
ANY_CHAR (.|\n)
-PUNCT [?!:'`]
-ACCENT \\[`'"^]
+PUNCT [][()?!:'`]
SPECIAL_CHAR [&@]
NATIONAL [\001-\006\021-\027\031\036]
-TEX {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}|{SPECIAL_CHAR}
-DASHED_WORD {A}({AN}|-)*
-DASHED_KEY_WORD \\{DASHED_WORD}
+TEX {AA}|-|{PUNCT}|{NATIONAL}|{SPECIAL_CHAR}
+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 __
/* produce requested token */
int type = scm_to_int (scm_caar (extra_tokens_));
- yylval.scm = scm_cdar (extra_tokens_);
+ yylval = scm_cdar (extra_tokens_);
extra_tokens_ = scm_cdr (extra_tokens_);
if (scm_is_null (extra_tokens_))
yy_pop_state ();
/* produce requested token */
int type = scm_to_int (scm_caar (extra_tokens_));
- yylval.scm = scm_cdar (extra_tokens_);
+ yylval = scm_cdar (extra_tokens_);
extra_tokens_ = scm_cdr (extra_tokens_);
if (scm_is_null (extra_tokens_))
yy_pop_state ();
yy_push_state (longcomment);
}
%[^{\n\r][^\n\r]*[\n\r] {
+ (void) YYText_utf8 ();
}
%[^{\n\r] { // backup rule
+ (void) YYText_utf8 ();
}
%[\n\r] {
}
%[^{\n\r][^\n\r]* {
+ (void) YYText_utf8 ();
}
{WHITE}+ {
yy_push_state (sourcefileline);
}
<version>\"[^"]*\" { /* got the version number */
- string s (YYText () + 1);
+ string s (YYText_utf8 () + 1);
s = s.substr (0, s.rfind ('\"'));
yy_pop_state ();
SCM top_scope = scm_car (scm_last_pair (scopes_));
scm_module_define (top_scope, ly_symbol2scm ("version-seen"), SCM_BOOL_T);
- if (!is_valid_version (s))
+ if (!is_valid_version (s)) {
+ yylval = SCM_UNSPECIFIED;
return INVALID;
-
-
+ }
}
-<sourcefilename>\"[^"]*\" {
- string s (YYText () + 1);
+<sourcefilename>\"[^""]*\" {
+ string s (YYText_utf8 () + 1);
s = s.substr (0, s.rfind ('\"'));
yy_pop_state ();
}
<longcomment>{
[^\%]* {
+ (void) YYText_utf8 ();
}
\%*[^}%]* {
-
+ (void) YYText_utf8 ();
}
"%"+"}" {
yy_pop_state ();
<INITIAL,chords,lyrics,figures,notes>\\include {
yy_push_state (incl);
}
-<incl>\"[^"]*\" { /* got the include file name */
- string s (YYText ()+1);
+<incl>\"[^""]*\" { /* got the include file name */
+ string s (YYText_utf8 ()+1);
s = s.substr (0, s.rfind ('"'));
new_input (s, sources_);
yy_pop_state ();
}
<incl>\\{BLACK}*{WHITE}? { /* got the include identifier */
- string s = YYText () + 1;
+ string s = YYText_utf8 () + 1;
strip_trailing_white (s);
if (s.length () && (s[s.length () - 1] == ';'))
s = s.substr (0, 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,version,sourcefilename>\"[^"]* { // 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);
}
+
+ /* 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);
+ yylval = scm_from_locale_string (s);
return RESTNAME;
}
+<chords,notes,figures>q/[-_] | // pseudo backup rule
+<chords,notes,figures>q {
+ yylval = SCM_UNSPECIFIED;
+ return CHORD_REPETITION;
+}
+
+<chords,notes,figures>R/[-_] | // pseudo backup rule
<chords,notes,figures>R {
+ yylval = SCM_UNSPECIFIED;
return MULTI_MEASURE_REST;
}
<INITIAL,chords,figures,lyrics,markup,notes># { //embedded scm
}
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 ();
-
- yylval.scm = sval;
+ yylval = sval;
return SCM_TOKEN;
}
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++)
{
}
char_count_stack_.back () += n;
- return scan_scm_id (sval);
+ sval = eval_scm (sval, '$');
+
+ int token = scan_scm_id (sval);
+ if (!scm_is_eq (yylval, SCM_UNSPECIFIED))
+ return token;
}
<INITIAL,notes,lyrics>{
\<\< {
+ yylval = SCM_UNSPECIFIED;
return DOUBLE_ANGLE_OPEN;
}
\>\> {
+ yylval = SCM_UNSPECIFIED;
return DOUBLE_ANGLE_CLOSE;
}
}
<INITIAL,notes>{
\< {
+ yylval = SCM_UNSPECIFIED;
return ANGLE_OPEN;
}
\> {
+ yylval = SCM_UNSPECIFIED;
return ANGLE_CLOSE;
}
}
<figures>{
_ {
+ yylval = SCM_UNSPECIFIED;
return FIGURE_SPACE;
}
\> {
+ yylval = SCM_UNSPECIFIED;
return FIGURE_CLOSE;
}
\< {
+ yylval = SCM_UNSPECIFIED;
return FIGURE_OPEN;
}
}
<notes,figures>{
- {ALPHAWORD} {
- return scan_bare_word (YYText ());
+ {WORD}/[-_] | // backup rule
+ {WORD} {
+ return scan_bare_word (YYText_utf8 ());
}
- {NOTECOMMAND} {
- return scan_escaped_word (YYText () + 1);
+ {COMMAND}/[-_] | // backup rule
+ {COMMAND} {
+ return scan_escaped_word (YYText_utf8 () + 1);
}
{FRACTION} {
- yylval.scm = scan_fraction (YYText ());
+ yylval = scan_fraction (YYText ());
return FRACTION;
}
{UNSIGNED}/\/ | // backup rule
{UNSIGNED} {
- yylval.scm = scm_c_read_string (YYText ());
+ yylval = scm_c_read_string (YYText ());
return UNSIGNED;
}
{E_UNSIGNED} {
- yylval.i = String_convert::dec2int (string (YYText () +1));
+ yylval = scm_c_read_string (YYText () + 1);
return E_UNSIGNED;
}
}
<quote,lyric_quote>{
\\{ESCAPED} {
- *yylval.string += to_string (escaped_char (YYText ()[1]));
+ char c = escaped_char (YYText ()[1]);
+ yylval = scm_cons (scm_from_locale_stringn (&c, 1),
+ yylval);
}
[^\\""]+ {
- *yylval.string += YYText ();
+ yylval = scm_cons (scm_from_locale_string (YYText_utf8 ()),
+ yylval);
}
\" {
yy_pop_state ();
/* yylval is union. Must remember STRING before setting SCM*/
- string *sp = yylval.string;
- yylval.scm = ly_string2scm (*sp);
- delete sp;
+
+ yylval = scm_string_concatenate_reverse (yylval,
+ SCM_UNDEFINED,
+ SCM_UNDEFINED);
+
return is_lyric_state () ? LYRICS_STRING : STRING;
}
- . {
- *yylval.string += YYText ();
+ \\ {
+ yylval = scm_cons (scm_from_locale_string (YYText ()),
+ yylval);
}
}
start_lyric_quote ();
}
{FRACTION} {
- yylval.scm = scan_fraction (YYText ());
+ yylval = 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 ());
+ yylval = scm_c_read_string (YYText ());
return UNSIGNED;
}
- {NOTECOMMAND} {
- return scan_escaped_word (YYText () + 1);
+ {COMMAND}/[-_] | // backup rule
+ {COMMAND} {
+ return scan_escaped_word (YYText_utf8 () + 1);
}
{LYRICS} {
/* ugr. This sux. */
- string s (YYText ());
+ string s (YYText_utf8 ());
+ yylval = SCM_UNSPECIFIED;
if (s == "__")
- return yylval.i = EXTENDER;
+ return EXTENDER;
if (s == "--")
- return yylval.i = HYPHEN;
+ return HYPHEN;
s = lyric_fudge (s);
char c = s[s.length () - 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_string2scm (s);
+ yylval = ly_string2scm (s);
return LYRICS_STRING;
}
. {
- return YYText ()[0];
+ yylval = SCM_UNSPECIFIED;
+ return YYText ()[0]; // LYRICS already catches all multibytes.
}
}
<chords>{
- {ALPHAWORD} {
- return scan_bare_word (YYText ());
+ {WORD}/[-_] | // backup rule
+ {WORD} {
+ return scan_bare_word (YYText_utf8 ());
}
- {NOTECOMMAND} {
- return scan_escaped_word (YYText () + 1);
+ {COMMAND}/[-_] | // backup rule
+ {COMMAND} {
+ return scan_escaped_word (YYText_utf8 () + 1);
}
{FRACTION} {
- yylval.scm = scan_fraction (YYText ());
+ yylval = 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 ());
+ yylval = scm_c_read_string (YYText ());
return UNSIGNED;
}
- {
+ yylval = SCM_UNSPECIFIED;
return CHORD_MINUS;
}
: {
+ yylval = SCM_UNSPECIFIED;
return CHORD_COLON;
}
\/\+ {
+ yylval = SCM_UNSPECIFIED;
return CHORD_BASS;
}
\/ {
+ yylval = SCM_UNSPECIFIED;
return CHORD_SLASH;
}
\^ {
+ yylval = SCM_UNSPECIFIED;
return CHORD_CARET;
}
. {
- return YYText ()[0];
+ yylval = SCM_UNSPECIFIED;
+ return YYText ()[0]; // WORD catches all multibyte.
}
}
<markup>{
\\score {
+ yylval = SCM_UNSPECIFIED;
return SCORE;
}
- {MARKUPCOMMAND} {
- string str (YYText () + 1);
+ {COMMAND}/[-_] | // backup rule
+ {COMMAND} {
+ string str (YYText_utf8 () + 1);
int token_type = MARKUP_FUNCTION;
SCM s = lookup_markup_command (str);
// in reverse order, so the first token pushed in the
// loop will be EXPECT_NO_MORE_ARGS.
- yylval.scm = scm_car(s);
+ yylval = scm_car(s);
// yylval now contains the function to call as token
// value (for token type MARKUP_FUNCTION or
return token_type;
}
[{}] {
+ yylval = SCM_UNSPECIFIED;
return YYText ()[0];
}
[^$#{}\"\\ \t\n\r\f]+ {
- string s (YYText ());
-
- char c = s[s.length () - 1];
- /* brace open is for not confusing dumb tools. */
- if (c == '{' || c == '}')
- here_input ().warning (
- _ ("Brace found at end of markup. Did you forget a space?"));
- yylval.scm = ly_string2scm (s);
-
+ string s (YYText_utf8 ());
+ yylval = ly_string2scm (s);
return STRING;
}
. {
- return YYText()[0];
+ yylval = SCM_UNSPECIFIED;
+ return YYText()[0]; // Above is catchall for multibyte
}
}
<longcomment><<EOF>> {
LexerError (_ ("EOF found inside a comment").c_str ());
is_main_input_ = false; // should be safe , can't have \include in --safe.
+ yylval = SCM_UNSPECIFIED;
if (!close_input ())
yyterminate (); // can't move this, since it actually rets a YY_NULL
}
-<<EOF>> { if (is_main_input_)
+<<EOF>> {
+ yylval = SCM_UNSPECIFIED;
+ if (is_main_input_)
{
/* 2 = init.ly + current file.
> because we're before closing, but is_main_input_ should
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} {
- return scan_bare_word (YYText ());
+ {WORD}/[-_] | // backup rule
+ {WORD} {
+ return scan_bare_word (YYText_utf8 ());
}
- {DASHED_KEY_WORD} {
- return scan_escaped_word (YYText () + 1);
+ {COMMAND}/[-_] | // backup rule
+ {COMMAND} {
+ return scan_escaped_word (YYText_utf8 () + 1);
}
}
+{FRACTION} {
+ yylval = scan_fraction (YYText ());
+ return FRACTION;
+}
+
-{UNSIGNED} | // backup rule
{REAL} {
- yylval.scm = scm_c_read_string (YYText ());
- return REAL;
-}
--\. { // backup rule
- yylval.scm = scm_from_double (0.0);
+ yylval = scm_c_read_string (YYText ());
return REAL;
}
+{UNSIGNED}/\/ | // backup rule
{UNSIGNED} {
- yylval.scm = scm_c_read_string (YYText ());
+ yylval = scm_c_read_string (YYText ());
return UNSIGNED;
}
[{}] {
-
+ yylval = SCM_UNSPECIFIED;
return YYText ()[0];
}
-[*:=] {
- char c = YYText ()[0];
- return c;
+-/\. | // backup rule
+[*:=] {
+ yylval = SCM_UNSPECIFIED;
+ return YYText ()[0];
}
<INITIAL,notes,figures>. {
+ yylval = SCM_UNSPECIFIED;
return YYText ()[0];
}
<INITIAL,lyrics,notes,figures>\\. {
+ yylval = SCM_UNSPECIFIED;
char c = YYText ()[1];
switch (c) {
}
}
-<*>. {
- string msg = _f ("invalid character: `%c'", YYText ()[0]);
+<*>.[\200-\277]* {
+ string msg = _f ("invalid character: `%s'", YYText_utf8 ());
LexerError (msg.c_str ());
- return YYText ()[0];
+ yylval = SCM_UNSPECIFIED;
+ return '%'; // Better not return half a utf8 character.
}
%%
}
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
Lily_lexer::pop_state ()
{
+ bool extra = (YYSTATE == extratoken);
+
+ if (extra)
+ yy_pop_state ();
+
if (YYSTATE == notes || YYSTATE == chords)
pitchname_tab_stack_ = scm_cdr (pitchname_tab_stack_);
yy_pop_state ();
+
+ if (extra) {
+ hidden_state_ = YYSTATE;
+ yy_push_state (extratoken);
+ }
}
int
Lily_lexer::identifier_type (SCM sid)
{
- int k = try_special_identifiers (&yylval.scm , sid);
+ int k = try_special_identifiers (&yylval , sid);
return k >= 0 ? k : SCM_IDENTIFIER;
}
// SCM sym = ly_symbol2scm (str.c_str ());
+ yylval = SCM_UNSPECIFIED;
int i = lookup_keyword (str);
if (i == MARKUP && is_lyric_state ())
return LYRIC_MARKUP;
string msg (_f ("unknown escaped string: `\\%s'", str));
LexerError (msg.c_str ());
- yylval.scm = ly_string2scm (str);
+ yylval = ly_string2scm (str);
return STRING;
}
{
int funtype = SCM_FUNCTION;
- yylval.scm = get_music_function_transform (sid);
+ yylval = sid;
- SCM s = scm_object_property (yylval.scm, ly_symbol2scm ("music-function-signature"));
+ SCM s = get_music_function_signature (sid);
SCM cs = scm_car (s);
if (scm_is_pair (cs))
}
return funtype;
}
- yylval.scm = sid;
+ yylval = sid;
return identifier_type (sid);
}
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);
- if (unsmob_pitch (yylval.scm))
+ yylval = scm_cdr (handle);
+ if (unsmob_pitch (yylval))
return (YYSTATE == notes) ? NOTENAME_PITCH : TONICNAME_PITCH;
- else if (scm_is_symbol (yylval.scm))
+ else if (scm_is_symbol (yylval))
return DRUM_PITCH;
}
else if ((YYSTATE == chords)
&& (handle = scm_hashq_get_handle (chordmodifier_tab_, sym))!= SCM_BOOL_F)
{
- yylval.scm = scm_cdr (handle);
+ yylval = scm_cdr (handle);
return CHORD_MODIFIER;
}
- if ((chord_repetition_.repetition_symbol_ != SCM_EOL)
- && to_boolean (scm_equal_p (chord_repetition_.repetition_symbol_, sym)))
- return CHORD_REPETITION;
}
-
- yylval.scm = ly_string2scm (str);
+ yylval = ly_string2scm (str);
return STRING;
}
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_UNSPECIFIED))
+ push_extra_token (token, yylval);
+ break;
+ case '#':
+ push_extra_token (SCM_IDENTIFIER, scm_car (v));
+ break;
+ }
+ }
+ sval = scm_car (sval);
+ } else
+ sval = SCM_UNSPECIFIED;
+ }
+
return sval;
}
+/* Check for valid UTF-8 that has no overlong or surrogate codes and
+ is in the range 0-0x10ffff */
+
+const char *
+Lily_lexer::YYText_utf8 ()
+{
+ const char * const p = YYText ();
+ for (int i=0; p[i];) {
+ if ((p[i] & 0xff) < 0x80) {
+ ++i;
+ continue;
+ }
+ int oldi = i; // start of character
+ int more = 0; // # of followup bytes, 0 if bad
+ switch (p[i++] & 0xff) {
+ // 0xc0 and 0xc1 are overlong prefixes for
+ // 0x00-0x3f and 0x40-0x7f respectively, bad.
+ case 0xc2: // 0x80-0xbf
+ case 0xc3: // 0xc0-0xff
+ case 0xc4: // 0x100-0x13f
+ case 0xc5: // 0x140-0x17f
+ case 0xc6: // 0x180-0x1bf
+ case 0xc7: // 0x1c0-0x1ff
+ case 0xc8: // 0x200-0x23f
+ case 0xc9: // 0x240-0x27f
+ case 0xca: // 0x280-0x2bf
+ case 0xcb: // 0x2c0-0x2ff
+ case 0xcc: // 0x300-0x33f
+ case 0xcd: // 0x340-0x37f
+ case 0xce: // 0x380-0x3bf
+ case 0xcf: // 0x3c0-0x3ff
+ case 0xd0: // 0x400-0x43f
+ case 0xd1: // 0x440-0x47f
+ case 0xd2: // 0x480-0x4bf
+ case 0xd3: // 0x4c0-0x4ff
+ case 0xd4: // 0x500-0x53f
+ case 0xd5: // 0x540-0x57f
+ case 0xd6: // 0x580-0x5bf
+ case 0xd7: // 0x5c0-0x5ff
+ case 0xd8: // 0x600-0x63f
+ case 0xd9: // 0x640-0x67f
+ case 0xda: // 0x680-0x6bf
+ case 0xdb: // 0x6c0-0x6ff
+ case 0xdc: // 0x700-0x73f
+ case 0xdd: // 0x740-0x77f
+ case 0xde: // 0x780-0x7bf
+ case 0xdf: // 0x7c0-0x7ff
+ more = 1; // 2-byte sequences, 0x80-0x7ff
+ break;
+ case 0xe0:
+ // don't allow overlong sequences for 0-0x7ff
+ if ((p[i] & 0xff) < 0xa0)
+ break;
+ case 0xe1: // 0x1000-0x1fff
+ case 0xe2: // 0x2000-0x2fff
+ case 0xe3: // 0x3000-0x3fff
+ case 0xe4: // 0x4000-0x4fff
+ case 0xe5: // 0x5000-0x5fff
+ case 0xe6: // 0x6000-0x6fff
+ case 0xe7: // 0x7000-0x7fff
+ case 0xe8: // 0x8000-0x8fff
+ case 0xe9: // 0x9000-0x9fff
+ case 0xea: // 0xa000-0xafff
+ case 0xeb: // 0xb000-0xbfff
+ case 0xec: // 0xc000-0xcfff
+ more = 2; // 3-byte sequences, 0x7ff-0xcfff
+ break;
+ case 0xed: // 0xd000-0xdfff
+ // Don't allow surrogate codes 0xd800-0xdfff
+ if ((p[i] & 0xff) >= 0xa0)
+ break;
+ case 0xee: // 0xe000-0xefff
+ case 0xef: // 0xf000-0xffff
+ more = 2; // 3-byte sequences,
+ // 0xd000-0xd7ff, 0xe000-0xffff
+ break;
+ case 0xf0:
+ // don't allow overlong sequences for 0-0xffff
+ if ((p[i] & 0xff) < 0x90)
+ break;
+ case 0xf1: // 0x40000-0x7ffff
+ case 0xf2: // 0x80000-0xbffff
+ case 0xf3: // 0xc0000-0xfffff
+ more = 3; // 4-byte sequences, 0x10000-0xfffff
+ break;
+ case 0xf4:
+ // don't allow more than 0x10ffff
+ if ((p[i] & 0xff) >= 0x90)
+ break;
+ more = 3; // 4-byte sequence, 0x100000-0x10ffff
+ break;
+ }
+ if (more) {
+ // check that all continuation bytes are valid
+ do {
+ if ((p[i++] & 0xc0) != 0x80)
+ break;
+ } while (--more);
+ if (!more)
+ continue;
+ }
+ Input h = here_input ();
+ h.set (h.get_source_file (), h.start () + oldi, h.start () + i);
+ h.warning (_ ("non-UTF-8 input").c_str ());
+ }
+ return p;
+}
/*
/*
- 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;
-
- 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);
- }
+ size_t i=0;
- return s;
+ while ((i = s.find ('_', i)) != string::npos)
+ {
+ s[i++] = ' ';
+ }
+ return s;
}
/*