]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/lexer.l
release: 0.1.9
[lilypond.git] / lily / lexer.l
index 6f5945a60544bfaac62a223bbbc1ce7551f78f40..8e702b7c793d00b52041edad18b5473f1d298d2f 100644 (file)
 %{ // -*-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 "notename.hh"
-#include "lexer.hh"
+#include "my-lily-lexer.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);\
+       yylval.string = new String
+
+#define yylval (*(YYSTYPE*)lexval_l)
 
+#define YY_USER_ACTION add_lexed_char(YYLeng());
 %}
 
 %option c++
 %option noyywrap
 %option nodefault
-%option yylineno
 %option debug
-%option yyclass="My_flex_lexer"
+%option yyclass="My_lily_lexer"
 %option stack
+%option never-interactive 
+%option warn
 
-%x notes
 %x incl
-%x quote
+%x header
 %x lyrics
-
+%x notes
+%x quote
+%x longcomment
 
 
 A              [a-zA-Z]
 AA             {A}|_
 N              [0-9]
 AN             {AA}|{N}
-PUNCT          [?!,.:;]
-ACCENT         [\\'"^]
+PUNCT          [?!,.:;']
+ACCENT         \\[`'"^]
 NATIONAL       [\241-\377]
 TEX            {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}
 
 WORD           {A}{AN}*
 ALPHAWORD      {A}+
 INT            -?{N}+
-REAL           {INT}?(\.{N}*)?
-
-OPTSIGN                !?
-PITCHMOD       ['`]*{OPTSIGN}
-RESTNAME       r|s|p
-NOTECOMMAND    \\{WORD}
-NOTENAME       [a-z]+
-UNOTENAME      [A-Z][a-z]*
-DOTS           \.+
-LYRICS         {TEX}+
-COMMENT                [%#].*\n
+REAL           ({INT}\.{N}*)|(-?\.{N}+)
+KEYWORD                \\{WORD}
+WHITE          [ \n\t\f]
+HORIZONTALWHITE                [ \t]
+BLACK          [^ \n\t\f]
+RESTNAME       [rs]
+NOTECOMMAND    \\{A}+
+LYRICS         ({AA}|{NATIONAL})[^0-9 \t\n\f]*
 
 %%
 
-\$             {
-       yy_push_state(notes); 
-}
 
-\@             {
-       yy_push_state(lyrics); 
-}
+<notes,incl,INITIAL,lyrics>{
+  "%{" {
+       yy_push_state(longcomment);
+  }
+  %[^{\n].*\n  {
+  }
+  %[^{\n]      { // backup rule
+  }
+  %\n  {
+  }
+  %[^{\n].*    {
+  }
+  {WHITE}+     {
 
-<notes>{RESTNAME}      {
-       const char *s = YYText();
-       yylval.string = new String (s); 
-       mtor << "rest:"<< yylval.string;
-       return RESTNAME;
-}
-<notes>{UNOTENAME}     {
-       int *p=yylval.ii;
-       return ret_notename(p, YYText(), -1);
+  }
 }
 
-<notes>{NOTENAME}      {
-       int *p=yylval.ii;
-       return ret_notename(p, YYText(), 0);
+<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}*        {
+       }
 
-<notes>{NOTECOMMAND}   {
-       String c = YYText() +1;
-       mtor << "\\word: " << YYText()+1<<eol;
-       int l = lookup_keyword(c);
-       if (l != -1)
-               return l;
-       Identifier * id = lookup_identifier(c);
-       if (id) {               
-               yylval.id = id;
-               return IDENTIFIER;
+       .               {
+               return YYText()[0];
        }
-       String *sp = new String( c);
-       yylval.string=sp;
-       return STRING;
 }
 
-<notes>{PITCHMOD}      {
-       const char *s = YYText();
-       mtor << "pitchmod:"<< YYText()<<eol;
-       yylval.string = new String (s);
-       return PITCHMOD;
+
+<notes,INITIAL,lyrics>\\include           {
+       yy_push_state(incl);
 }
-<notes>{DOTS}          {
-       yylval.i = strlen(YYText());
-       return DOTS;
+<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_l_g);
+       yy_pop_state();
 }
-<notes>{INT}           {
-       yylval.i = String_convert::dec2_i( String( YYText() ) );
-       return INT;
+<incl>\"[^"]*   { // backup rule
+       cerr << "missing end quote" << endl;
+       exit( 1 );
 }
-<notes>{COMMENT}       {
+<notes>{RESTNAME}      {
+       const char *s = YYText();
+       yylval.string = new String (s); 
+       DOUT << "rest:"<< yylval.string;
+       return RESTNAME;
 }
-<notes>[ \t\n]+                {
-
+<INITIAL,lyrics,notes>\\\${BLACK}*{WHITE}      {
+       String s=YYText() + 2;
+       s=s.left_str(s.length_i() - 1);
+       return scan_escaped_word(s);
 }
-<notes>\$      {
-       yy_pop_state();
+<INITIAL,lyrics,notes>\${BLACK}*{WHITE}                {
+       String s=YYText() + 1;
+       s=s.left_str(s.length_i() - 1);
+       return scan_bare_word(s);
 }
-<notes>\"[^"]*\" {
-       String s (YYText()+1);
-       s = s.left_str(s.length_i()-1);
-       yylval.string = new String(s);
-       return STRING;
+<INITIAL,lyrics,notes>\\\${BLACK}*             { // backup rule
+       cerr << "white expected" << endl;
+       exit( 1 );
 }
-<notes>.       {
-       return yylval.c = YYText()[0];
+<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());
 
-\"             {
-       yy_push_state(quote);
-}
-<quote>[^"]*   {
-       yylval.string = new String (YYText());
-}
-<quote>\"      {
-       mtor << "quoted string\n";
-       yy_pop_state();
-       return STRING;
+       }
+
+       {NOTECOMMAND}   {
+               return scan_escaped_word(YYText()+1);
+       }
+
+       {INT}           {
+               yylval.i = String_convert::dec2_i( String( YYText() ) );
+               return INT;
+       }
+
+       \" {
+               start_quote();
+       }
 }
 
-<lyrics>{DOTS}         {
-       yylval.i = strlen(YYText());
-       return DOTS;
+\"             {
+       start_quote();
 }
-<lyrics>{INT}          {
-       yylval.i = String_convert::dec2_i( String( YYText() ) );
-       return INT;
+<quote>{
+       \\\\    {
+               *yylval.string += '\\';
+       }
+       \\\"    {
+               *yylval.string +='\"';
+       }
+       [^"]+   {
+               *yylval.string += YYText();
+       }
+       \"      {
+               DOUT << "quoted string: `" << *yylval.string << "'\n";
+               yy_pop_state();
+               return STRING;
+       }
 }
-<lyrics>{NOTECOMMAND}  {
-       String c = YYText() +1;
-       mtor << "\\word: " << YYText()+1<<eol;
-       int l = lookup_keyword(c);
-       if (l != -1)
-               return l;
 
-/* let's try passing tex's typesetting macros like \ss \alpha \c */
-       String* str_p = new String(YYText());//huh?
-       return STRING;  
+<lyrics>{
 
-/* and skip identifiers...
-       Identifier * id = lookup_identifier(c);
-       if (id) {               
-               yylval.id = id;
-               return IDENTIFIER;
+       \" {
+               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;
        }
-       String *sp = new String( c);
+       . {
+               return yylval.c = YYText()[0];
+       }
+}
 
-       yylval.string=sp;
-       return STRING;
-*/
+<<EOF>> {
+       DOUT << "<<eof>>";
+
+       if (! close_input()) { 
+         yyterminate(); // can't move this, since it actually rets a YY_NULL
+       }
 }
-<lyrics>\"[^"]*\" {
-       String s (YYText()+1);
-       s = s.left_str(s.length_i()-1);
-       yylval.string = new String(s);
-       return STRING;
+{WORD} {
+       return scan_bare_word(YYText());
 }
-<lyrics>{LYRICS} {
-       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);
-       return STRING;
+{KEYWORD}      {
+       return scan_escaped_word(YYText()+1);
 }
-<lyrics>\|     {
-       return YYText()[0];
+{REAL}         {
+       Real r;
+       int cnv=sscanf (YYText(), "%lf", &r);
+       assert(cnv == 1);
+       DOUT  << "REAL" << r<<'\n';
+       yylval.real = r;
+       return REAL;
 }
-<lyrics>{COMMENT}              { 
 
+{INT}  {
+       yylval.i = String_convert::dec2_i( String( YYText() ) );
+       return INT;
 }
-<lyrics>[{}]   {
+
+[{}]   {
+
+       DOUT << "parens\n";
        return YYText()[0];
 }
-<lyrics>[()\[\]|/.^>_-] {
+[*:=]          {
+       char c = YYText()[0];
+       DOUT << "misc char" <<c<<"\n";
+       return c;
+}
+
+<INITIAL,notes>.       {
        return yylval.c = YYText()[0];
 }
-<lyrics>[ \t\n]+               {
+
+<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;
+    }
 }
-<lyrics>@      {
-       yy_pop_state();
+
+<*>.           {
+       LexerError( String( "illegal character: " ) +String( YYText()[0] ));
+       return YYText()[0];
 }
 
-<<EOF>> {
-       mtor << "<<EOF>>";
+%%
 
-       if (! close_input())
-         yyterminate(); // can't move this, since it actually rets a YY_NULL
+void
+My_lily_lexer::push_note_state()
+{
+       yy_push_state(notes);
 }
 
-
-include           {
-       yy_push_state(incl);
+void
+My_lily_lexer::push_lyric_state()
+{
+       yy_push_state(lyrics);
 }
-<incl>[ \t]*      { /* eat the whitespace */ }
-<incl>\"[^"]*\"+   { /* got the include file name */
-   String s (YYText()+1);
-   s = s.left_str(s.length_i()-1);
-   defined_ch_c_l = here_ch_c_l() - String( YYText() ).length_i() - 1;
-   new_input(s);
-   yy_pop_state();
+void
+My_lily_lexer::pop_state()
+{
+       yy_pop_state();
 }
 
-
-{WORD}         {
-       mtor << "word: " << YYText()<<eol;
-       String c = YYText();
-       int l = lookup_keyword(c);
-       if (l != -1)
+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(c);
-       if (id) {               
+       }
+       Identifier * id = lookup_identifier(str);
+       if (id) {
+               DOUT << "(identifier)\n";
                yylval.id = id;
-               return IDENTIFIER;
+               return id->token_code_i_;
        }
-       String *sp = new String( c);
-       mtor << "new id: " << *sp << eol;
+       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;
 }
 
-{REAL}         {
-       Real r;
-       int cnv=sscanf (YYText(), "%lf", &r);
-       assert(cnv == 1);
-       mtor  << "REAL" << r<<'\n';
-       yylval.real = r;
-       return REAL;
-}
-
-[{}]   {
+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;
+               }
+       }
 
-       mtor << "parens\n";
-       return YYText()[0];
+       yylval.string=new String( str );
+       return STRING;
 }
-[*:=]          {
-       char c = YYText()[0];
-       mtor << "misc char" <<c<<"\n";
-       return c;
+
+bool
+My_lily_lexer::note_state_b() const
+{
+       return YY_START == notes;
 }
-[ \t\n]+       {
-       
+
+bool
+My_lily_lexer::lyric_state_b() const
+{
+       return YY_START == lyrics;
 }
 
-{COMMENT}              {
-       //ignore
+void 
+My_lily_lexer::push_header_state() 
+{
+       yy_push_state(header);
 }
-.              {
-       error( String( "illegal character: " ) + String( YYText()[0] ), here_ch_c_l() );
-       return YYText()[0];
+
+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);
 
+}