--- /dev/null
+%{ // -*-Fundamental-*-
+/*
+ lexer.l -- implement the Flex lexer
+
+ source file of the LilyPond music typesetter
+
+ (c) 1996,1997 Han-Wen Nienhuys <hanwen@stack.nl>
+*/
+
+
+/*
+ backup rules
+
+ after making a change to the lexer rules, run
+ flex -b <this lexer file>
+ and make sure that
+ lex.backup
+ contains no backup states, but only the reminder
+ Compressed tables always back up.
+ (don-t forget to rm lex.yy.cc :-)
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "string.hh"
+#include "string-convert.hh"
+#include "my-lily-lexer.hh"
+#include "varray.hh"
+#include "interval.hh"
+#include "parser.hh"
+#include "debug.hh"
+#include "parseconstruct.hh"
+#include "main.hh"
+#include "identifier.hh"
+void strip_trailing_white (String&);
+void strip_leading_white (String&);
+
+
+#define start_quote() \
+ yy_push_state (quote);\
+ yylval.string = new String
+
+#define yylval (*(YYSTYPE*)lexval_l)
+
+#define YY_USER_ACTION add_lexed_char (YYLeng ());
+%}
+
+%option c++
+%option noyywrap
+%option nodefault
+%option debug
+%option yyclass="My_lily_lexer"
+%option stack
+%option never-interactive
+%option warn
+
+%x incl
+%x lyrics
+%x notes
+%x quote
+%x longcomment
+
+
+A [a-zA-Z]
+AA {A}|_
+N [0-9]
+AN {AA}|{N}
+PUNCT [?!:']
+ACCENT \\[`'"^]
+NATIONAL [\001-\006\021-\027\031\036\200-\377]
+TEX {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}
+WORD {A}{AN}*
+ALPHAWORD {A}+
+DIGIT {N}
+UNSIGNED {N}+
+INT -?{UNSIGNED}
+REAL ({INT}\.{N}*)|(-?\.{N}+)
+KEYWORD \\{WORD}
+WHITE [ \n\t\f]
+HORIZONTALWHITE [ \t]
+BLACK [^ \n\t\f]
+RESTNAME [rs]
+NOTECOMMAND \\{A}+
+LYRICS ({AA}|{TEX})[^0-9 \t\n\f]*
+ESCAPED [nt\\'"]
+PLET \\\[
+TELP \\\]
+
+%%
+
+
+<*>\r {
+ // windows-suck-suck-suck
+}
+
+<notes,incl,INITIAL,lyrics>{
+ "%{" {
+ yy_push_state (longcomment);
+ }
+ %[^{\n].*\n {
+ }
+ %[^{\n] { // backup rule
+ }
+ %\n {
+ }
+ %[^{\n].* {
+ }
+ {WHITE}+ {
+
+ }
+}
+
+<longcomment>{
+ [^\%]* {
+ }
+ \%*[^}%]* {
+
+ }
+ "%"+"}" {
+ yy_pop_state ();
+ }
+ <<EOF>> {
+ LexerError ("EOF found inside a comment");
+ if (! close_input ())
+ yyterminate (); // can't move this, since it actually rets a YY_NULL
+ }
+}
+
+
+
+<notes,INITIAL,lyrics>\\include {
+ yy_push_state (incl);
+}
+<incl>\"[^"]*\" { /* got the include file name */
+ String s (YYText ()+1);
+ s = s.left_str (s.length_i ()-1);
+ DOUT << "#include `" << s << "\'\n";
+ new_input (s,source_global_l);
+ yy_pop_state ();
+}
+<incl>\"[^"]* { // backup rule
+ cerr << "missing end quote" << endl;
+ exit (1);
+}
+<notes>{RESTNAME} {
+ const char *s = YYText ();
+ yylval.string = new String (s);
+ DOUT << "rest:"<< yylval.string;
+ return RESTNAME;
+}
+<INITIAL,lyrics,notes>\\\${BLACK}*{WHITE} {
+ String s=YYText () + 2;
+ s=s.left_str (s.length_i () - 1);
+ return scan_escaped_word (s);
+}
+<INITIAL,lyrics,notes>\${BLACK}*{WHITE} {
+ String s=YYText () + 1;
+ s=s.left_str (s.length_i () - 1);
+ return scan_bare_word (s);
+}
+<INITIAL,lyrics,notes>\\\${BLACK}* { // backup rule
+ cerr << "white expected" << endl;
+ exit (1);
+}
+<INITIAL,lyrics,notes>\${BLACK}* { // backup rule
+ cerr << "white expected" << endl;
+ exit (1);
+}
+<notes>{
+ {ALPHAWORD}/\' {
+ post_quotes_b_ = true;
+ return scan_bare_word (YYText ());
+ }
+ \'+ {
+ yylval.i = YYLeng ();
+ if (post_quotes_b_) {
+ post_quotes_b_ = false;
+ return POST_QUOTES;
+ } else
+ return PRE_QUOTES;
+ }
+ {ALPHAWORD} {
+ return scan_bare_word (YYText ());
+
+ }
+
+ {NOTECOMMAND} {
+ return scan_escaped_word (YYText ()+1);
+ }
+
+ {DIGIT} {
+ yylval.i = String_convert::dec2_i (String (YYText ()));
+ return DIGIT;
+ }
+
+ {UNSIGNED} {
+ yylval.i = String_convert::dec2_i (String (YYText ()));
+ return UNSIGNED;
+ }
+
+ \" {
+ start_quote ();
+ }
+}
+
+\" {
+ start_quote ();
+}
+<quote>{
+ \\{ESCAPED} {
+ *yylval.string += escaped_char(YYText()[1]);
+ }
+ [^\\"]+ {
+ *yylval.string += YYText ();
+ }
+ \" {
+ DOUT << "quoted string: `" << *yylval.string << "'\n";
+ yy_pop_state ();
+ return STRING;
+ }
+ . {
+ *yylval.string += YYText ();
+ }
+}
+
+<lyrics>{
+
+ \" {
+ start_quote ();
+ }
+ {UNSIGNED} {
+ yylval.i = String_convert::dec2_i (String (YYText ()));
+ return UNSIGNED;
+ }
+ {NOTECOMMAND} {
+ 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";
+ return STRING;
+ }
+ . {
+ return yylval.c = YYText ()[0];
+ }
+}
+
+<<EOF>> {
+ DOUT << "<<eof>>";
+
+ 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);
+}
+{REAL} {
+ Real r;
+ int cnv=sscanf (YYText (), "%lf", &r);
+ assert (cnv == 1);
+ DOUT << "REAL" << r<<'\n';
+ yylval.real = r;
+ return REAL;
+}
+
+{UNSIGNED} {
+ yylval.i = String_convert::dec2_i (String (YYText ()));
+ return UNSIGNED;
+}
+
+[{}] {
+
+ DOUT << "parens\n";
+ return YYText ()[0];
+}
+[*:=] {
+ char c = YYText ()[0];
+ DOUT << "misc char" <<c<<"\n";
+ return c;
+}
+
+<lyrics,notes>{PLET} {
+ return yylval.i = PLET;
+}
+
+<lyrics,notes>{TELP} {
+ return yylval.i = TELP;
+}
+
+<INITIAL,notes>. {
+ return yylval.c = YYText ()[0];
+}
+
+<INITIAL,lyrics,notes>\\. {
+ char c= YYText ()[1];
+ yylval.c = c;
+ switch (c) {
+ case '>':
+ return E_BIGGER;
+ case '<':
+ return E_SMALLER;
+ case '!':
+ return E_EXCLAMATION;
+ default:
+ return E_CHAR;
+ }
+}
+
+<*>. {
+ String msg= String ("illegal character: ") +String (YYText ()[0]);
+ LexerError (msg.ch_C ());
+ return YYText ()[0];
+}
+
+%%
+
+void
+My_lily_lexer::push_note_state ()
+{
+ yy_push_state (notes);
+}
+
+void
+My_lily_lexer::push_lyric_state ()
+{
+ yy_push_state (lyrics);
+}
+void
+My_lily_lexer::pop_state ()
+{
+ yy_pop_state ();
+}
+
+int
+My_lily_lexer::scan_escaped_word (String str)
+{
+ DOUT << "\\word: `" << str<<"'\n";
+ 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;
+ return NOTENAME_ID;
+ }
+ }
+ String msg ("Unknown escaped string: `" + str + "'");
+ LexerError (msg.ch_C ());
+ DOUT << "(string)";
+ String *sp = new String (str);
+ yylval.string=sp;
+ 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;
+ return NOTENAME_ID;
+ }
+ }
+
+ yylval.string=new String (str);
+ return STRING;
+}
+
+bool
+My_lily_lexer::note_state_b () const
+{
+ return YY_START == notes;
+}
+
+bool
+My_lily_lexer::lyric_state_b () const
+{
+ return YY_START == lyrics;
+}
+
+void
+strip_trailing_white (String&s)
+{
+ int i=0;
+ for (; i < s.length_i (); i++)
+ if (!isspace (s[i]))
+ break;
+
+ s = s.nomid_str (0, i);
+}
+
+void
+strip_leading_white (String&s)
+{
+ int i=s.length_i ();
+ while (i--)
+ if (!isspace (s[i]))
+ break;
+
+ s = s.left_str (i+1);
+}