FLEX/YACC 多行输入中第一行的末尾

FLEX/YACC End of the first line in multiline input

提问人:Mimoa 提问时间:5/30/2023 最后编辑:Mimoa 更新时间:5/30/2023 访问量:27

问:

我再次来这里寻求建议,提前致谢。 我有简单的解析器来解析字符并将数字相加。 当我只有一行时,没关系,但它应该从多行文件中读取。 它一直持续到派生的末尾,当它应该接受 STMTS + '\n' 时,它会说“无效字符”。它看不到 \n。

        //lex
%{
#include "kfloat.tab.h"
%}

%option nounput
%option noinput

%%
[ \t]   ;

[0-9]+  { yylval.d=atof(yytext); return NUMBER; }
"sqrt"  {return iSQRT; }
"log"   {return iLOG; }
"+"     { return OPLUS; } 
"-"     { return OMINUS; }
"*"     { return OMULT; } 
"/"     { return ODIV; } 
"("     { return LPAR; }
")"     { return RPAR; }
"\n"    { yylineno++; return yytext[0]; }
";"     { return EOL;}
.   return yytext[0];
%%

//yacc

%{
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define YYDEBUG 1
void yyerror(char *);
int yylex(void);
extern int yylineno;

%}
%union { double d;}
%token <d> NUMBER
%token EOL
%type <d> EXP STMT 
%left OPLUS OMINUS
%left OMULT ODIV
%left iLOG iSQRT 
%left LPAR RPAR


%%
STMTS : STMTS STMT EOL {printf("END of deriv :2 and MORE statements- now EOF and next line\n");} //edit
      | STMT EOL {printf("END of deriv :ONE statement - now EOF and next line\n");} //edit
      | STMTS '\n'  //edit
     ;
STMT : EXP
     |   
     ;
EXP  : EXP OPLUS EXP   {$$=$1+$3; printf("ENDdddd1111:  %f\n",$1);}
     | EXP OMINUS EXP  {$$=$1-$3;}
     | EXP OMULT EXP   {$$=$1*$3;}
     | EXP ODIV EXP    {if ($3==0) {yyerror("Zatim nelze delit nulou"); exit(0);} else {$$=$1/$3;}}
     | LPAR EXP RPAR   { ;}
     | iSQRT EXP       {$$=sqrt($2);}
     | iLOG EXP        {$$=log10($2);}
     | OPLUS EXP       {$$= $2;}
     | OMINUS EXP      {$$= -$2;}
     | NUMBER          {$$= $1;}
     ;

%%

/* lineno do erroru printf*/

int main(void)
{
#if YYDEBUG
  yydebug = 1;
#endif
  if(!yyparse ())
    printf("OK\n");
  return 0;
}
  
void yyerror (char *s)
{
   printf("Syntakticka chyba: %s na radku: %i\n",s,yylineno);
}

执行时,最终一切看起来都很好,只是它不会将 STMTS 与 '\n' 组合在一起。 在这种情况下,我做错了什么?

  • EOL 是 ';' - 它应该是“方程”的末尾
  • 行示例:(+5+-5)*8--10;
Stack now 0 8 17
Reducing stack by rule 2 (line 28):
   $1 = nterm STMT ()
   $2 = token EOL ()
**-> $$ = nterm STMTS ()
Entering state 7
Stack now 0 7
Reading a token
Next token is token "invalid token" ()**
Error: popping nterm STMTS ()
Stack now 0
Cleanup: discarding lookahead token "invalid token" ()
Stack now 0
ENDdddd1111:  5.000000
ENDddd333:  10.000000
Syntakticka chyba: syntax error na radku: 1

编辑:好的,我更进一步: 将“\n”作为尾行添加到 parser.y 中。Lex 是一样的。现在它适用于在 bash 中手动插入的字符串 - 第一个字符串 - 调用第二个 STMTS 中的操作,第二个字符串 - 第一个 STMTS 被调用。看起来不错。但是当我尝试解析文件中的输入时,当它应该是 EOF 时,我再次得到无效的字符:


//from file 
END of deriv :ONE statement - now EOF and next line
-> $$ = nterm STMTS ()
Entering state 7
Stack now 0 7
Reading a token
Next token is token "invalid token" ()   //should be '\n'
Syntaktick▒ chyba
Error: popping nterm STMTS ()
Stack now 0
Cleanup: discarding lookahead token "invalid token" ()
Stack now 0

// manual insert - same string
END of deriv :ONE statement - now EOF and next line
-> $$ = nterm STMTS ()
Entering state 7
Stack now 0 7
Reading a token
Next token is token '\n' ()
Shifting token '\n' ()
Entering state 16
Stack now 0 7 16
Reducing stack by rule 3 (line 26):
   $1 = nterm STMTS ()
   $2 = token '\n' ()
-> $$ = nterm STMTS ()
Entering state 7
Stack now 0 7
Reading a token


// Content of input file:
(+12-9);
sqrt(16);

如果我尝试手动输入这些,它可以正常工作。

YACC EOF LEX

评论


答:

0赞 Chris Dodd 5/30/2023 #1

词法分析器返回换行符的标记,但解析器不需要它。如果你想让换行符结束 STMT,你需要一个期望这样的规则——类似于 .'\n'STMTS : STMT '\n'

或者,将词法分析器更改为忽略换行符。您可能还想忽略其他空格,因此类似于

[ \t\r\n]         ;

在 LEX 代码中

评论

0赞 Mimoa 5/30/2023
我已将“\n”EOF 添加到 STMTS 中,它可以正常工作。但仅用于输入,而不是从文件输入。在那里,EOF再次是无效的令牌。请参见 EDIT 中的更改。Y 文件。
0赞 Mimoa 5/30/2023
问题确实出在\r中。文件中的行尾有 CR。很多工作...但是“如果你不燃烧,你就不知道火”再次感谢多德先生。