Код Yacc читает как IF, так и ELSE - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть программа-улитка, которая должна интерпретироваться моим кодом Yacc. Однако у меня возникли проблемы с синтаксическим анализом оператора IF-ELSE в исходном коде улитки из файла .y

Это моя программа Snail

print "Start of Program"; 
print newline;
print 4+5*2;
print newline;
//testing  3 < 4
if (3 < 4) then 
print "3 is smaller than 4"; 
print newline;  
else
print "your interpreter is not working"; 
endif

Это моя (.l) flex code (Lexical Analyzer)

%{
#include "y.tab.h"
#include <string.h>
#include <stdlib.h>
int linenum=1;
int temp_int;
char temp_str[200];
%}
%%

\n     {linenum++;}

[\t ]          /* skip spaces */;
\/\/[^\n]*     /* ignore comments */;

"+"        {return '+';}
"-"        {return '-';} 
"*"        {return '*';} 
"/"        {return '/';} 
")"        {return ')';}
"("        {return '(';}
"<"        {return '<';}
">"        {return '>';}
";"        {return ';';}
"print"    {return PRINT;}
"newline"  {return NEWLINE;}
"if"    {return IF;}
"then"  {return THEN;}
"else"    {return ELSE;}
"endif"  {return ENDIF;}

[0-9]+   {sscanf(yytext, "%d", &temp_int);
          yylval.int_val = temp_int;
          return INT;}

\"[^"\n]*\" {strncpy(temp_str, &(yytext[1]), strlen(yytext)-2);
             temp_str[strlen(yytext)-2] = (char) 0;
             yylval.str_val = temp_str;
             return STRING;}

.  {printf("LEX: unknown input string found in line %d \n", linenum); abort();}

%% 

int yywrap()  {return 1;}

Это мой (.y) код yacc

/* Put new code here */

%{
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    int yyerror(char *s);
    extern int linenum;
%}

/* define all types of variables and terminals */

%union
{
  int int_val;
  char *str_val;
}

/* define the individual types of variables and terminals */

%token PRINT
%token NEWLINE
%token IF
%token THEN
%token ELSE
%token ENDIF
%token <str_val> STRING
%token <int_val> INT
%type <int_val> expr

/* assign priorities to operators in order to avoid shift/reduce conflicts (grammar ambiguities) */

%left '+' '-'
%left '*' '/'
%left '<' '>'
%left UMINUS

/* the start variable of your program */

%start program

%%

program : stmt_list 
        | error       {printf("YACC: syntax error near line %d \n", linenum);
                       abort();}
        ;

stmt_list : stmt_list stmt
          | stmt
          ; 

stmt    :   print_stmt
        |   if_stmt

print_stmt  : expr ';'              {printf("expression found\n");} 
            | PRINT expr ';'        {if (top() == 1) then {printf("%d", $2);}}
            | PRINT STRING ';'      {printf("%s", $2);} 
            | PRINT NEWLINE ';'     {printf("\n");}

if_stmt : IF expr THEN {top()==1 ? push($2!=0) : push(0);} stmt_list {pop();}
        | ELSE {top()==1 ? push($2==0) : push(0);} stmt_list {pop();} ENDIF

expr : '(' expr ')'     {$$ = $2;}
     | expr '+' expr    {$$ = $1 + $3;}
     | expr '-' expr    {$$ = $1 - $3;}
     | expr '*' expr    {$$ = $1 * $3;}
     | expr '/' expr    {$$ = $1 / $3;}
     | expr '<' expr    {$$ = $1 < $3;}
     | expr '>' expr    {$$ = $1 > $3;}
     | expr '<=' expr    {$$ = $1 >= $3;}
     | expr '>=' expr    {$$ = $1 <= $3;}
     | expr '==' expr    {$$ = $1 == $3;}
     | expr '!=' expr    {$$ = $1 != $3;}
     | '-' expr         %prec UMINUS {$$ = -$2;}
     | INT              {$$ = $1;}
     ;

%%

/* link lex code */
/* #include "lex.yy.c" */
/* insert additional code here */

int main(void)
{
    return yyparse();
}

int yyerror(char *s)
{
    fprintf(stderr, "%s \n",s);
}

Это мой фактический вывод

Start of Program
14
3 is smaller than 4
your interpreter is not working

Этомой ожидаемый результат

Start of Program
14
3 is smaller than 4

Может кто-нибудь помочь с некоторыми советами о том, как правильно проанализировать оператор IF-ELSE? Спасибо!

1 Ответ

2 голосов
/ 02 ноября 2019

Вы печатаете STRING и NEWLINE безоговорочно, даже если эти отпечатки находятся внутри if и поэтому могут быть недооценены. Вам необходим тест if (top() == 1) в этих правилах, так же как и в действии PRINT expr.

Вам необходимо четко понимать различие между разбором выражения и оценивая утверждение. Вам нужно разобрать все безоговорочно, так как вы узнаете программу. Вы хотите оценивать операторов, только когда вы находитесь в контексте, который вы оцениваете, который вы записываете в свой стек - top() == 1 означает, что вы находитесь в контексте, который хотите оценить, тогда как top() == 0означает, что вы находитесь в контексте, который НЕ оценивает (просто анализирует). Для строгой корректности вы также должны проверять top() во всех ваших правилах выражений и не оценивать, когда оно равно 0. На практике это не имеет значения для вещей без побочных эффектов - вы можете оценивать их безоговорочно и нене имеет значения;вы просто проигнорируете значение, вычисленное в неоцененном контексте.

...