Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

"Решение проблем при создании парсера для языка Pascal с помощью YACC и FLEX"

Delphi , Компоненты и Классы , TParser

В данной статье мы рассмотрим решение проблем, которые могут возникнуть при создании парсера для языка Pascal с помощью YACC и FLEX. Мы будем использовать пример простого парсера, который обрабатывает объявления целых чисел, некоторые базовые выражения и операторы if-else.

Описание проблемы

При создании парсера для языка Pascal с помощью YACC и FLEX может возникнуть проблема, когда парсер не может найти ошибку, несмотря на то, что терминал выдает сообщение об ошибке "Error at line:0", что кажется невозможным. В данном случае мы будем использовать Flex для создания лексического анализатора, а YACC для создания синтаксического анализатора.

Контекст

Ниже приведены файлы лексического анализатора (lex.l) и синтаксического анализатора (grammar.y), а также пример входных данных, которые вызывают ошибку в строке 1.

lex.l:

%{
#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];
%%

grammar.y:

%{
#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, i3, 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.

Подтвержденный ответ

Проблема заключается в том, что лексический анализатор возвращает пробелы и табуляции как токены, но грамматика не распознает их. Чтобы решить эту проблему, нужно добавить правило парсера:

[ \t\r]    { }

Это позволяет добраться до строки 6 вместо строки 0 перед возникновением ошибки. Ошибка на строке 0 возникает потому, что между объявлениями не допускаются-semicolon.

Чтобы исправить это, нужно изменить грамматику, как показано ниже:

dec_block:
        dec_block dec
        |
        dec
        ;

dec:
        int_dec_list semiColon
        ;

Также нужно изменить правило logical_expression, чтобы оно могло дойти до терминала expression:

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

После внесения этих изменений парсер должен правильно обрабатывать входные данные без ошибок.

Альтернативный ответ

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

Заключение

В данной статье мы рассмотрели решение проблем, которые могут возникнуть при создании парсера для языка Pascal с помощью YACC и FLEX. Мы использовали пример простого парсера и показали, как исправить ошибки, связанные с неправильным расположением точек с запятой и нераспознаванием пробелов и табуляций. Также мы предложили альтернативный подход к отладке грамматик с помощью YYDEBUG.

Создано по материалам из источника по ссылке.

В данной статье рассматривается решение проблем, возникающих при создании парсера для языка Pascal с помощью YACC и FLEX, с использованием примера простого парсера, обрабатывающего объявления целых чисел, базовые выражения и операторы if-else.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: TParser ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-19 13:29:56
2024-11-21 12:12:14/0.0039000511169434/0