не может найти простую ошибку при разборе с YACC - PullRequest
1 голос
/ 25 марта 2012

Я пытаюсь создать очень простой парсер YACC на языке Pascal, который просто включает в себя целочисленные объявления, некоторые базовые выражения и операторы if-else.однако, я не могу найти ошибку в течение нескольких часов, и я скоро сойду с ума.терминал говорит Error at line:0 но это невозможно !.Я использую flex и byacc для парсера. Я буду очень рад, если вы сможете мне помочь.это мой файл lex, как вы можете видеть;

%{
#include <stdio.h>
#include <string.h>
#include "y.tab.h"
extern int yylval;
int linenum=0;
%}

digit   [0-9]
letter  [A-Za-z]

%%
if              return IF;
then                return THEN;
else                return ELSE;
for             return FOR;
while               return WHILE;
PROGRAM             return PROGRAM_SYM;
BEGIN               return BEGIN_SYM;
VAR             return VAR_SYM;
END             return END_SYM;
INTEGER             return INTEGER_SYM;
{letter}({letter}|{digit})* return identifier;
[0-9]+              return NUMBER;
[\<][\=]            return CON_LE;
[\>][\=]            return CON_GE;
[\=]                return CON_EQ;          
[\:][\=]            return ASSIGNOP;
;               return semiColon;
,               return comma;
\n              {linenum++;}
.               return (int) yytext[0];
%%

, и это мой файл Yacc

%{
#include <stdio.h>
#include <string.h>
#include "y.tab.h"
extern FILE *yyin;
extern int linenum;
%}

%token PROGRAM_SYM VAR_SYM BEGIN_SYM END_SYM INTEGER_SYM NUMBER
%token identifier INTEGER ASSIGNOP semiColon comma THEN
%token IF ELSE FOR WHILE
%token CON_EQ CON_LE CON_GE GE LE

%left '*' '/'
%left '+' '-'

%start program

%%

program: PROGRAM_SYM identifier semiColon VAR_SYM dec_block BEGIN_SYM statement_list END_SYM '.'
     ;

dec_block:
        dec_list semiColon;

dec_list:
        dec_list dec
        |
        dec
        ;

dec: 
        int_dec_list
        ;

int_dec_list:   
        int_dec_list int_dec ':' type
        |
        int_dec ':' type
        ;

int_dec:
        int_dec comma identifier
        |
        identifier
        ;

type:
    INTEGER_SYM
    ;

statement_list:
        statement_list statement
        |
        statement
        ;

statement:
        assignment_list
        |
        expression_list
        |
        selection_list
        ;

assignment_list:
        assignment_list assignment
        |
        assignment      
        ;

assignment:

        identifier ASSIGNOP expression_list
        ;

expression_list:
        expression_list expression semiColon
        |
        expression semiColon
        ;


expression:
        '(' expression ')'
        |
        expression '*' expression
        |
        expression '/' expression
        |
        expression '+' expression
        |
        expression '-' expression
        |
        factor
        ;

factor:     
        identifier
        |
        NUMBER
        ;


selection_list:
        selection_list selection
        |
        selection
        ;

selection:
        IF '(' logical_expression ')' THEN statement_list ELSE statement_list
        ;


logical_expression:
        logical_expression '=' expression
        |
        logical_expression '>' expression
        |
        logical_expression '<' expression
        ;


%%
void yyerror(char *s){
    fprintf(stderr,"Error at line: %d\n",linenum);
}
int yywrap(){
    return 1;
}
int main(int argc, char *argv[])
{
    /* Call the lexer, then quit. */
    yyin=fopen(argv[1],"r");
    yyparse();
    fclose(yyin);
    return 0;
}

и, наконец, я получаю ошибку в первой строке, когда я даю ввод;

PROGRAM myprogram;

VAR

i:INTEGER;

i3:INTEGER;

j:INTEGER;

BEGIN

i := 3;

j := 5;

i3 := i+j*2;

i := j*20;

if(i>j)

then i3 := i+50+(45*i+(40*j));

else i3 := i+50+(45*i+(40*j))+i+50+(45*i+(30*j));

END.

Ответы [ 2 ]

1 голос
/ 25 марта 2012

Для отладки грамматики YYDEBUG - ваш друг.Либо вставьте #define YYDEBUG 1 в %{ .. %} в верхней части вашего .y файла, либо скомпилируйте с -DYYDEBUG, и вставьте yydebug = 1; в main перед вызовом yyparse, иполучить информацию о том, какие токены видит синтаксический анализатор и что он делает с ними ....

0 голосов
/ 25 марта 2012

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

Добавьте правило синтаксического анализа:

[ \t\r]    { }

Это приведет вас к строке 6 вместострока 0, прежде чем вы столкнетесь с ошибкой.Вы получаете эту ошибку, потому что не допускаете точки с запятой между объявлениями:

dec_block:
        dec_list semiColon;

dec_list:
        dec_list dec
        |
        dec
        ;

dec:
        int_dec_list
        ;

Вероятно, это должно быть:

dec_block:
        dec_block dec
        |
        dec
        ;

dec:
        int_dec_list semiColon
        ;

В результате вы попадете на строку 14 во входных данных.

Кстати, одна из первых вещей, которые я сделал, - убедиться, что лексический анализатор сообщает мне, что он делает, изменив правила следующим образом:

if              { printf("IF\n"); return IF; }

В долгосрочном коде яd сделать этот диагностический вывод выбираемым во время выполнения.


У вас есть общая проблема с точкой с запятой.Также не ясно, что вы должны разрешить expression_list в правиле для statement (или, может быть, «еще нет» - это может быть уместно, когда у вас есть вызовы функций, но допускается 3 + 2 / 4 в качестве «оператора»не очень полезно).


Эта грамматика доходит до конца ввода:

%{
#include <stdio.h>
#include <string.h>
#include "y.tab.h"
extern FILE *yyin;
extern int linenum;
%}

%token PROGRAM_SYM VAR_SYM BEGIN_SYM END_SYM INTEGER_SYM NUMBER
%token identifier INTEGER ASSIGNOP semiColon comma THEN
%token IF ELSE FOR WHILE
%token CON_EQ CON_LE CON_GE GE LE

%left '*' '/'
%left '+' '-'

%start program

%%

program: PROGRAM_SYM identifier semiColon VAR_SYM dec_block BEGIN_SYM statement_list END_SYM '.'
     ;

dec_block:
        dec_block dec
        |
        dec
        ;

dec:
        int_dec_list semiColon
        ;

int_dec_list:
        int_dec_list int_dec ':' type
        |
        int_dec ':' type
        ;

int_dec:
        int_dec comma identifier
        |
        identifier
        ;

type:
    INTEGER_SYM
    ;

statement_list:
        statement_list statement
        |
        statement
        ;

statement:
        assignment
        |
        selection
        ;

assignment:
        identifier ASSIGNOP expression semiColon
        ;

expression:
        '(' expression ')'
        |
        expression '*' expression
        |
        expression '/' expression
        |
        expression '+' expression
        |
        expression '-' expression
        |
        factor
        ;

factor:
        identifier
        |
        NUMBER
        ;

selection:
        IF '(' logical_expression ')' THEN statement_list ELSE statement_list
        ;

logical_expression:
        expression '=' expression
        |
        expression '>' expression
        |
        expression '<' expression
        ;

%%
void yyerror(char *s){
    fprintf(stderr,"Error at line: %d\n",linenum);
}
int yywrap(){
    return 1;
}
int main(int argc, char *argv[])
{
    /* Call the lexer, then quit. */
    yyin=fopen(argv[1],"r");
    yyparse();
    fclose(yyin);
    return 0;
}

Основные изменения включают в себя удаление assignment_list и expression_list и изменение logical_expression так что две стороны расширения - expression, а не LHS, являющийся logical_expression (который тогда никогда не имел примитивного определения, что приводило к проблемам с предупреждениями).

Есть еще проблемы сразрешить;expression_list в selection должно быть более ограничительным для точного отражения грамматики Паскаля.(Вам нужен блок, где это может быть один оператор или BEGIN, список операторов, END.)

...