Lex和Yacc的语法错误是由扫描仪或解析器引起的

问题描述 投票:0回答:1

我在Lex和Yacc中很陌生。我尝试学习语法规则和语义动作。我试图编写一个解析器,该解析器基本上可以执行赋值,函数声明,函数调用和打印语句。问题是我输入后,输出为语法错误。所以我在想我的语法会导致这种情况,但我不确定。这是我的文件:

scanner.flx:

%option noyywrap
%option yylineno

%{

#include "parser.tab.h"

%}

IDENT [a-zA-Z_][a-zA-Z0-9_]*
INT -?[0-9]+
STRING "[\S\s]*?"
UNFSTRING "[\S\s]*?[^"]$

%%
"int" return tINT;
"string" return tSTRING;
"return" return tRETURN;
"print" return tPRINT;
"(" return tLPAR;
")" return tRPAR;
"," return tCOMMA;
"%" return tMOD;
"=" return tASSIGNM;
"-" return tMINUS;
"+" return tPLUS;
"/" return tDIV;
"*" return tSTAR;
";" return tSEMI;
"{" return tLBRAC;
"}" return tRBRAC;
{IDENT} return tIDENT;
{INT} return tINTVAL;
{STRING} return tSTRINGVAL;
{UNFSTRING} return tUNFSTRING;
[ \t\n]+
. { /* pass any other character to the parser */
  return yytext[0];
}
%%

parser.y:

%{
#include <stdio.h>

void yyerror (const char *s)
{
    printf ("%s\n", s);
}
%}

%token tINT tSTRING tRETURN tPRINT tLPAR tRPAR tCOMMA tMOD tASSIGNM tMINUS tPLUS tDIV tSTAR tSEMI tLBRAC tRBRAC tIDENT tINTVAL tSTRINGVAL tUNFSTRING

%left '='
%left '+' '-'
%left '*' '/'
%left '(' ')'


%%

CVD19       :              stmtlst
;

stmtlst     :              stmtlst stmt
            |              stmt
            ;

stmt        :              funcDecl
            |              varDecl
            |              assgnmt
            |              callfunc
            |              printstmt
            ;

funcDecl    :              type tIDENT '(' ')' '{' funcbody return '}'              {  printf("FUNCTION ");  }
            |              type tIDENT '(' funcparams ')' '{' funcbody return '}'   {  printf("FUNCTION W/PARAMS ");  }
            ;

funcbody    :              varDecl
            |              assgnmt
            |              callfunc
            |              printstmt
            ;

return      :              tRETURN expr ';'
            ;

funcparams  :              funcparams ',' type tIDENT
            |              type tIDENT
            ;

varDecl     :              type vars '=' expr ';'
            ;

type        :              tINT              {  printf("INT TYPE ");  }
            |              tSTRING           {  printf("STRING TYPE ");  }
            ;

assgnmt     :              tIDENT '=' expr ';'           {  printf("ASSIGNMENT");  }
            ;

callfunc    :              tIDENT '(' ')' ';'            {  printf("FUNCTION CALL");  }
            |              tIDENT '(' vars ')' ';'       {  printf("FUNCTION W/PARAMs CALL");  }
            ;

printstmt   :              tPRINT '(' expr ')' ';'          {  printf("PRINTSTMT 1");  }
            |              tPRINT '(' callfunc ')' ';'      {  printf("PRINTSTMT 2");  }
            ;


vars        :              vars ',' tIDENT
            |              tIDENT            {  printf("IDENT ");  }
            ;

expr        :              value
            |              expr '+' expr     {    $$  =  $1  +  $3;  }
            |              expr '-' expr     {    $$  =  $1  -  $3;  }
            |              expr '*' expr     {    $$  =  $1  *  $3;  }
            |              expr '/' expr     {    $$  =  $1  /  $3;  }
            ;         

value       :              tINTVAL                                {  printf("INTVAL ");  }
            |              tSTRINGVAL                             {  printf("STRINGVAL ");  }
            |              tUNFSTRING                             {  printf("UNFSTRING ");  }
            /*|              tIDENT    MIGHT BE PROBLEMATIC     { $$ = $1; }*/
            ;

%%

int main ()
{
   if (yyparse()) {
   // parse error
       printf("ERROR\n");
       return 1;
   }
   else {
   // successful parsing
      printf("OK\n");
      return 0;
   }
}

虽然我尝试在MacOS Terminal中运行文件,但仍正常使用这些命令:

flex scanner.flx

-没有问题-

bison -d parser.y

-没有问题-

gcc -o program lex.yy.c parser.tab.c -ll

-警告-

parser.tab.c:1330:16: warning: implicit declaration of function 'yylex' is invalid in C99
      [-Wimplicit-function-declaration]
      yychar = YYLEX;
               ^
parser.tab.c:686:16: note: expanded from macro 'YYLEX'
# define YYLEX yylex ()
               ^
1 warning generated.

这里是parser.tab.c中的1330行:

/* First try to decide what to do without reference to look-ahead token.  */
  yyn = yypact[yystate];
  if (yyn == YYPACT_NINF)
    goto yydefault;

  /* Not known => get a look-ahead token if don't already have one.  */

  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
  if (yychar == YYEMPTY)
    {
      YYDPRINTF ((stderr, "Reading a token: "));
      yychar = YYLEX;  /* THIS IS LINE 1330 <=============================================
    }

  if (yychar <= YYEOF)
    {
      yychar = yytoken = YYEOF;
      YYDPRINTF ((stderr, "Now at end of input.\n"));
    }
  else
    {
      yytoken = YYTRANSLATE (yychar);
      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
    }

这是我的输入:

input1:

int num = 123;

输出1:

INT TYPE IDENT syntax error
ERROR

input2:

print("str");

输出2:

syntax error
ERROR

input3:

int func(int i) {
 i = 5; 
 return i;
}

输出3:

INT TYPE IDENT syntax error
ERROR
bison flex-lexer yacc lex ambiguous-grammar
1个回答
0
投票

您的基本问题是,您在语法中使用字符文字(这很好),但没有在词法分析器中返回它们(这不好)。

代替

"(" return tLPAR;
")" return tRPAR;
// etc.

只要让这些字符落入您的后备规则:

.  { return yytext[0]; }

然后,由于您使用的是单字符文字,因此您也可以摆脱这些单字符标记的%token定义。

很遗憾,您不能使用更长的令牌来做到这一点。因此,您的关键字标记必须保持原样。

此外,您的字符串规则完全错误。请阅读(f)lex regular expressions的文档,而不要依赖其他正则表达式语法。 Flex无法识别\S\s转义符。它不执行非贪婪重复(*?)。它确实使用"作为特殊语法(意思是用引号引起来的文字字符串)-实际上,您已经在其他规则中使用了它,因此您不应该期望"成为STRING格式的常规字符。而且$不能在宏中使用(实际上,没有充分的理由在此扫描程序定义中使用宏;除非有充分的理由,否则我始终建议避免使用它们。)

一个可能的字符串操作是:

["]([^"]|\\.|\\\n)*["]   { return tSTRINGVAL; }

[我强烈建议您阅读debugging your grammar的野牛手册中的章节,尤其是有关如何启用解析器跟踪的部分,这比将printf调用插入解析器操作中更为准确和有用。 (实际上,这将向您显示您的问题。)


您的问题与编译器生成的警告无关,但是您应该解决该问题。这是因为您尚未在野牛序言中声明yylex。将其放在您对yyerror的定义之前:

int yylex(void);

以便编译器知道yylex的原型是什么。 (您必须声明它,因为野牛不会为您这样做。)

© www.soinside.com 2019 - 2024. All rights reserved.