Синтаксическая ошибка в Lex и Ya cc, вызванная сканером или анализатором - PullRequest
0 голосов
/ 24 апреля 2020

Я довольно новичок в Лексе и Я cc. Я пытаюсь узнать о правилах грамматики и действиях semanti c. Я пытался написать парсер, который в основном выполняет назначения, объявления функций, вызовы функций и операторы печати. Проблема в том, что после ввода я получаю вывод как синтаксическая ошибка . Так что я думаю, что моя грамматика вызывает это, но я не уверен. Вот мои файлы:

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.

Здесь около строки 1330 в файле parser.tab. c:

/* 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;

output1:

INT TYPE IDENT syntax error
ERROR

input2:

print("str");

output2:

syntax error
ERROR

input3:

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

output3:

INT TYPE IDENT syntax error
ERROR

1 Ответ

3 голосов
/ 24 апреля 2020

Ваша основная проблема c в том, что вы используете символьные литералы в своей грамматике (что хорошо), но не возвращаете их в своем лексере (что плохо).

Вместо

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

Просто дайте этим символам попасть в ваше правило отката:

.  { return yytext[0]; }

Тогда вы также можете избавиться от определений %token для этих односимвольных токенов, поскольку вы используете односимвольные литералы.

К сожалению, вы не можете сделать это с более длинными токенами. Таким образом, ваши жетоны ключевых слов должны оставаться такими, какие они есть.

Кроме того, ваше правило для строк совершенно неверно. Пожалуйста, прочитайте документацию для (f) lex регулярных выражений вместо того, чтобы полагаться на какой-то другой синтаксис регулярного выражения. Flex не распознает побеги \S и \s. Он не реализует нежадное повторение (*?). Он использует " в качестве специального синтаксиса (имеется в виду литеральные строки в кавычках) - фактически, вы использовали это в других правилах, поэтому не следует ожидать, что " будет обычным символом в вашем формате STRING , И $ нельзя использовать в макросе (и, действительно, нет веской причины использовать макросы в этом определении сканера; я всегда рекомендую избегать их, если для этого нет веских оснований.)

Одна возможная строка Действие:

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

Я настоятельно рекомендую вам прочитать главу руководства по бизонам о отладке грамматики , в частности, раздел о том, как включить трассировку парсера, что намного больше точнее и информативнее, чем вставка printf вызовов в действия парсера. (Это фактически показало бы вашу проблему.)


Ваша проблема не связана с предупреждением, выданным компилятором, но вы должны это исправить. Это происходит потому, что вы не объявили yylex в своем прологе бизонов. Поместите это непосредственно перед вашим определением yyerror:

int yylex(void);

, чтобы компилятор знал, что такое прототип yylex. (Вы должны объявить это, потому что бизон не делает этого за вас.)

...