]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/lexer.l
release: 0.1.9
[lilypond.git] / lily / lexer.l
index 560b49da11b83544a0905e22da60c47f96abd340..8e702b7c793d00b52041edad18b5473f1d298d2f 100644 (file)
@@ -1,6 +1,28 @@
 %{ // -*-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 "varray.hh"
 #include "parser.hh"
 #include "debug.hh"
-#include "input-score.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);\
 %option warn
 
 %x incl
+%x header
 %x lyrics
 %x notes
 %x quote
-
+%x longcomment
 
 
 A              [a-zA-Z]
@@ -50,40 +75,93 @@ TEX         {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}
 WORD           {A}{AN}*
 ALPHAWORD      {A}+
 INT            -?{N}+
-REAL           {INT}?(\.{N}*)?
+REAL           ({INT}\.{N}*)|(-?\.{N}+)
 KEYWORD                \\{WORD}
 WHITE          [ \n\t\f]
+HORIZONTALWHITE                [ \t]
 BLACK          [^ \n\t\f]
-RESTNAME       r
-NOTECOMMAND    \\{WORD}
-DOTS           \.+
-LYRICS         {AA}[^0-9 \t\n\f]*
-COMMENT                %.*\n
+RESTNAME       [rs]
+NOTECOMMAND    \\{A}+
+LYRICS         ({AA}|{NATIONAL})[^0-9 \t\n\f]*
 
 %%
 
-<lyrics,INITIAL,notes>{COMMENT}        {
+
+<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
+       }
+}
+<header>{
+       [\{\}]  {
+               return YYText()[0];
+       }
+       ^{WORD}         {
+               String s=YYText();
+               yylval.string = new String(s);
+               return FIELDNAME;
+       }
+       {HORIZONTALWHITE}+{BLACK}.*\n           {
+               String s=YYText();
+               strip_leading_white(s);
+               strip_trailing_white(s);
+               yylval.string = new String(s);
+               return RECORDLINE;
+       }
+       {WHITE}*        {
+       }
 
-include           {
+       .               {
+               return YYText()[0];
+       }
+}
+
+
+<notes,INITIAL,lyrics>\\include           {
        yy_push_state(incl);
 }
-<incl>{WHITE}*      { /* eat the whitespace */ }
 <incl>\"[^"]*\"   { /* got the include file name */
        String s (YYText()+1);
        s = s.left_str(s.length_i()-1);
-       mtor << "#include `" << s << "\'\n";
-//     defined_ch_C = here_ch_C() - String( YYText() ).length_i() - 1;
+       DOUT << "#include `" << s << "\'\n";
        new_input(s,source_l_g);
        yy_pop_state();
 }
-
+<incl>\"[^"]*   { // backup rule
+       cerr << "missing end quote" << endl;
+       exit( 1 );
+}
 <notes>{RESTNAME}      {
        const char *s = YYText();
        yylval.string = new String (s); 
-       mtor << "rest:"<< yylval.string;
+       DOUT << "rest:"<< yylval.string;
        return RESTNAME;
 }
 <INITIAL,lyrics,notes>\\\${BLACK}*{WHITE}      {
@@ -96,103 +174,100 @@ include           {
        s=s.left_str(s.length_i() - 1);
        return scan_bare_word(s);
 }
-<notes>{ALPHAWORD}/\'  {
-       post_quotes_b_ = true;
-       return scan_bare_word(YYText());
+<INITIAL,lyrics,notes>\\\${BLACK}*             { // backup rule
+       cerr << "white expected" << endl;
+       exit( 1 );
 }
-<notes>\'+             {
-       yylval.i = YYLeng();
-       if (post_quotes_b_) {
-               post_quotes_b_ = false;
-               return POST_QUOTES;
-       } else
-               return PRE_QUOTES;
+<INITIAL,lyrics,notes>\${BLACK}*               { // backup rule
+       cerr << "white expected" << endl;
+       exit( 1 );
 }
-<notes>{ALPHAWORD}     {
-       return scan_bare_word(YYText());
+<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());
 
-}
+       }
 
-<notes>{NOTECOMMAND}   {
-       return scan_escaped_word(YYText()+1);
-}
+       {NOTECOMMAND}   {
+               return scan_escaped_word(YYText()+1);
+       }
 
-<notes>{DOTS}          {
-       yylval.i = strlen(YYText());
-       return DOTS;
-}
-<notes>{INT}           {
-       yylval.i = String_convert::dec2_i( String( YYText() ) );
-       return INT;
-}
+       {INT}           {
+               yylval.i = String_convert::dec2_i( String( YYText() ) );
+               return INT;
+       }
 
-<notes>\+\+            {
-       return CONCAT;
-}
-<notes>\" {
-       start_quote();
+       \" {
+               start_quote();
+       }
 }
 
-
 \"             {
        start_quote();
 }
-<quote>\\\\    {
-       *yylval.string += '\\';
-}
-<quote>\\\"    {
-       *yylval.string +='\"';
-}
-<quote>[^"]+   {
-       *yylval.string += YYText();
-}
-<quote>\"      {
-       mtor << "quoted string: `" << *yylval.string << "'\n";
-       yy_pop_state();
-       return STRING;
+<quote>{
+       \\\\    {
+               *yylval.string += '\\';
+       }
+       \\\"    {
+               *yylval.string +='\"';
+       }
+       [^"]+   {
+               *yylval.string += YYText();
+       }
+       \"      {
+               DOUT << "quoted string: `" << *yylval.string << "'\n";
+               yy_pop_state();
+               return STRING;
+       }
 }
 
-<lyrics>\" {
-       start_quote();
-}
-<lyrics>{DOTS}         {
-       yylval.i = strlen(YYText());
-       return DOTS;
-}
-<lyrics>{INT}          {
-       yylval.i = String_convert::dec2_i( String( YYText() ) );
-       return INT;
-}
-<lyrics>{NOTECOMMAND}  {
-       return scan_escaped_word(YYText()+1);
-}
-<lyrics>{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);
-       mtor << "lyric : `" << s << "'\n";
-       return STRING;
-}
-<lyrics>\|     {
-       return YYText()[0];
-}
-<lyrics>[{}]   {
-       return YYText()[0];
-}
-<lyrics>[()\[\]|/.^>_-] {
-       return yylval.c = YYText()[0];
+<lyrics>{
+
+       \" {
+               start_quote();
+       }
+       {INT}           {
+               yylval.i = String_convert::dec2_i( String( YYText() ) );
+               return INT;
+       }
+       {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>> {
-       mtor << "<<eof>>";
+       DOUT << "<<eof>>";
 
        if (! close_input()) { 
          yyterminate(); // can't move this, since it actually rets a YY_NULL
@@ -208,30 +283,48 @@ include           {
        Real r;
        int cnv=sscanf (YYText(), "%lf", &r);
        assert(cnv == 1);
-       mtor  << "REAL" << r<<'\n';
+       DOUT  << "REAL" << r<<'\n';
        yylval.real = r;
        return REAL;
 }
 
+{INT}  {
+       yylval.i = String_convert::dec2_i( String( YYText() ) );
+       return INT;
+}
+
 [{}]   {
 
-       mtor << "parens\n";
+       DOUT << "parens\n";
        return YYText()[0];
 }
 [*:=]          {
        char c = YYText()[0];
-       mtor << "misc char" <<c<<"\n";
+       DOUT << "misc char" <<c<<"\n";
        return c;
 }
-<*>{WHITE}+    {
-       
-}
-<notes>.       {
+
+<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;
+    }
+}
+
 <*>.           {
-       error( String( "illegal character: " ) + String( YYText()[0] ), here_ch_C() );
+       LexerError( String( "illegal character: " ) +String( YYText()[0] ));
        return YYText()[0];
 }
 
@@ -257,25 +350,44 @@ My_lily_lexer::pop_state()
 int
 My_lily_lexer::scan_escaped_word(String str)
 {      
-       mtor << "\\word: `" << str<<"'\n";
+       DOUT << "\\word: `" << str<<"'\n";
        int l = lookup_keyword(str);
        if (l != -1) {
-               mtor << "(keyword)\n";
+               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;
+               }
+       }
+       LexerError( "Unknown escaped string: `" + str + "'");   
+       DOUT << "(string)";
        String *sp = new String( str);
        yylval.string=sp;
        return STRING;
 }
+
 int
 My_lily_lexer::scan_bare_word(String str)
 {
-       mtor << "word: `" << str<< "'\n";       
-       Identifier * id = lookup_identifier(str);
-       if (id) {
-               mtor << "(identifier)\n";
-               yylval.id = id;
-               return id->token_code_i_;
+       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 );
@@ -293,3 +405,29 @@ My_lily_lexer::lyric_state_b() const
 {
        return YY_START == lyrics;
 }
+
+void 
+My_lily_lexer::push_header_state() 
+{
+       yy_push_state(header);
+}
+
+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);
+
+}