1

「foo+1」の入力が与えられたとき、Lex が最初に識別子「foo」を返し、次に文字「+」、次に整数 1 を返すようにしたいと考えています。私が持っている文法の何らかの理由で、スペースを省略すると機能せず、「+」をスキップして「foo」と1を返すだけです。理由がわかりません。ここに問題があると思われるものはありますか?

%{
#include "expression.h"
#include "picoScanner.h"
static int block_comment_num = 0;
static char to_char(char *str);
int yylineno = 0;
%}

%option nodefault yyclass="FlexScanner" noyywrap c++


%x LINE_COMMENT
%x BLOCK_COMMENT

%%

Any                     { return pico::BisonParser::token::ANY; }
Int                     { return pico::BisonParser::token::INT; }
Float                   { return pico::BisonParser::token::FLOAT; }
Char                    { return pico::BisonParser::token::CHAR; }
List                    { return pico::BisonParser::token::LIST; }
Array                   { return pico::BisonParser::token::ARRAY; }
Table                   { return pico::BisonParser::token::TABLE; }
alg                     { return pico::BisonParser::token::ALG; }
if                      { return pico::BisonParser::token::IF; }
then                    { return pico::BisonParser::token::THEN; }
else                    { return pico::BisonParser::token::ELSE; }
is                      { return pico::BisonParser::token::IS; }
or                      { return pico::BisonParser::token::OR; }
and                     { return pico::BisonParser::token::AND; }
not                     { return pico::BisonParser::token::NOT; }
when                    { return pico::BisonParser::token::WHEN; }
[A-Z][a-zA-Z0-9_]*      { yylval->strval = new std::string(yytext); 
                          return pico::BisonParser::token::TYPENAME; }
[a-z_][a-zA-Z0-9_]*     { printf("saw '%s'\n", yytext); yylval->strval = new std::string(yytext); 
                          return pico::BisonParser::token::ID; }
"=="                    { return pico::BisonParser::token::EQ; }
"<="                    { return pico::BisonParser::token::LEQ; }
">="                    { return pico::BisonParser::token::GEQ; }
"!="                    { return pico::BisonParser::token::NEQ; }
"->"                    { return pico::BisonParser::token::RETURN; }
[\+\-\*/%]              { return yytext[0]; }

[-+]?[0-9]+             { yylval->ival = atoi(yytext); 
                          return pico::BisonParser::token::INT_LITERAL; }
([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?)  { yylval->fval = atof(yytext); 
                                               return pico::BisonParser::token::FLOAT_LITERAL; }
\"(\\.|[^\\"])*\"       { yylval->strval = new std::string(strndup(yytext+1, strlen(yytext) - 2)); 
                          return pico::BisonParser::token::STRING_LITERAL; }
\'(\\.|[^\\'])*\'       { yylval->cval = to_char(yytext+1); 
                          return pico::BisonParser::token::CHAR_LITERAL; }
[ \t\r]+                { /* ignore */ }
\n                      { yylineno++;  }
.                       { printf("~~~~~~~~~~munched %s\n", yytext); return yytext[0]; }

%%

static char to_char(char *str) {
   if (strlen(str) <= 1) {
      fprintf(stderr, "Error: empty character constant (line %d)\n", yylineno);
      exit(1);
   } else if (str[0] != '\\') {
      return str[0];
   } else {
      if (strlen(str) == 1) {
         fprintf(stderr, "Error: somehow we got a single slash character\n");
         exit(1);
      }
      switch (str[1]) {
         case 'n': return '\n';
         case 'r': return '\r';
         case 't': return '\t';
         case 'a': return '\a';
         case 'b': return '\b';
         case 'f': return '\f';
         case 'v': return '\v';
         case '\'': return '\'';
         case '"': return '"';
         case '\\': return '\\';
         case '?': return '\?';
         case 'x':
            fprintf(stderr, "Error: unicode not yet supported (line %d)\n", yylineno);
            exit(1);
         default:
            fprintf(stderr, "Error: unrecognized escape sequence '\\%c' (line %d)\n", 
                                                                     str[1], yylineno);
            exit(1);
      }
   }
}
4

2 に答える 2

3

私はlexに精通していませんが、次のことがエラーの原因であると確信しています:

[-+]?[0-9]+             { yylval->ival = atoi(yytext); 
                      return pico::BisonParser::token::INT_LITERAL; }

fooは識別子として解析されますが、「+0」はintリテラルとして解析されます (atoi変換により、符号は破棄されます)。

おそらく、レクサーレベルで符号なし数値リテラルのみを考慮し、パーサー レベルで符号を処理することをお勧めします (コンテキストに応じて+とトークンを異なる方法で処理します)。-これはあいまいさを解決するだけでなく、(C、C++、Java などで正当であるという意味で) "正しく" の- 5代わりになどの整数リテラルを解析することもできます-5

さらに、算術演算子のルールでエスケープするバックスラッシュは本当に必要ですか? 確かに、文字クラス内で特別な意味を持つ文字は-^、および]だけです (ただし、間違っている可能性があります)。

于 2013-07-26T01:25:38.417 に答える
1

and (an )foo+1として一致しているように見えます。関連スレッドを参照してください: 「最長-最早」の一致パターンを回避するために、ルールの優先順位を設定することは可能ですか?foo+1INT_LITERAL

明示的なルールをトークンとして追加して一致+させることもできます。そうしないと、Lex が可能な限り長い一致 (+1より長い+) を使用するように思えます。

于 2013-07-26T01:32:06.300 に答える