1

我希望 Lex 在输入“foo+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.

此外:算术运算符规则中的转义反斜杠真的有必要吗?Afaik,字符类中唯一具有特殊含义的字符是-, ^, and ](但我可能错了)。

于 2013-07-26T01:25:38.417 回答
1

在我看来,它与foo+1foo( +1an INT_LITERAL) 匹配。请参阅相关线程:是否可以为规则设置优先级以避免“最早”匹配模式?

您可以添加一个显式规则来匹配+作为标记,否则听起来 Lex 将采用最长的匹配(+1比 长+)。

于 2013-07-26T01:32:06.300 回答