Разбор в зубрах останавливается на первой линии - PullRequest
0 голосов
/ 06 апреля 2019

Я создаю грамматику бизонов на языке, подобном питону, и вывод, который я получаю при запуске моего файла тестового кода, таков:

found identifier a at line 2
memory exhausted

Parsing completed successfully

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

Я пытался уменьшить большую часть своей смены / не сводить ни к чему. Это действительно проблема, хотя? Потому что я думаю, что это не даст мне .exe

.l file

%{
#include <stdio.h>
#include <stdlib.h>
#include "sym_tab.h"
#include "define.h"

FILE *new_file;
int stringtoint;
int current_indent = 0;
void count();
void comment();
int count_indent();

%}



L                  [A-Za-z]
D                  [0-9]
N                  [1-9]
C   "%"|"!"|"@"|"$"|"%"|"^"|"&"|"_"



identifier          {L}({L}|{D})*
dec_const           (-|\+)*(0|{N}{D}*)
blank               [ \v\f]+
invalid_identifier  {D}|{C}(({L}|{D})*|{L})
invalid_keyword     {C}({L}|{D})+
block_count                 ^[\t]+


%%

"while"           {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(WHILE); }

"for"           {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(FOR); }
"in range"            {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(IN_RANGE); }

"input"           {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(INPUT); }
"print"           {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(PRINT); }

"if"              {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(IF); }
"elif"            {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(ELIF); }
"else"            {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(ELSE); }

"and"             {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(AND); }
"not"             {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(NOT); }
"or"              {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(OR); }

"return"          {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(RETURN); }
"exit"            {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(EXIT); }

"def"             {char *yycopy=strdup(yytext); count(); printf("found keyword %s at line %d\n" ,yycopy, line);
                        addsym( yycopy, block_num ); return(DEF); }

L?\"(\\.|[^\\"])*\" {char *yycopy=strdup(yytext); count(); printf("found literal string %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(STRING_LITERAL); }


{dec_const}               {char *yycopy=strdup(yytext); count(); stringtoint=atoi(yycopy);if(stringtoint<(-32768)|| stringtoint>32767){
              printf("dec_const %d in line %d not an acceptable value\n",stringtoint,line);}else{
              printf("found dec_constant %s at line %d\n", yycopy,line);
              addsym( yycopy, block_num ); return(DEC_CONST);}}


{identifier}              {char *yycopy=strdup(yytext); count(); if(strlen(yycopy)>20){
               printf("identifier %s in line %d not valid(longer than 20 characters)\n",yycopy,line);}
               else{printf("found identifier %s at line %d\n", yycopy,line);
                           addsym( yycopy, block_num ); return(IDENTIFIER);}}


"+"                       {char *yycopy=strdup(yytext); count(); printf("found symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(PLUS);}
"-"                       {char *yycopy=strdup(yytext); count(); printf("found symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(MINUS);}
"*"                       {char *yycopy=strdup(yytext); count(); printf("found symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(STAR);}
"/"                       {char *yycopy=strdup(yytext); count(); printf("found symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(DIV);}
"<"                       {char *yycopy=strdup(yytext); count(); printf("found equation_symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(L_THAN);}
">"                       {char *yycopy=strdup(yytext); count(); printf("found equation_symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(G_THAN);}
"=="                      {char *yycopy=strdup(yytext); count(); printf("found equation_symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(EQUAL);}
"<="                      {char *yycopy=strdup(yytext); count(); printf("found equation_symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(L_EQ_THAN);}
">="                      {char *yycopy=strdup(yytext); count(); printf("found equation_symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(G_EQ_THAN);}
"<>"                      {char *yycopy=strdup(yytext); count(); printf("found equation_symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(NEQUAL);}
":="                        {char *yycopy=strdup(yytext); count(); printf("found asign_symbol %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(ASSIGN);}
"("                       {char *yycopy=strdup(yytext); count(); printf("found %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(LPAREN);}
")"                       {char *yycopy=strdup(yytext); count(); printf("found %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(RPAREN);}

"["                       {char *yycopy=strdup(yytext); count(); printf("found %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(LSQUARE_BRACK);}
"]"                       {char *yycopy=strdup(yytext); count(); printf("found %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(RSQUARE_BRACK);}

"\n"                        {char *yycopy=strdup(yytext); count(); printf("found new line at line %d\n" , line);
                           addsym( yycopy, block_num ); return(END_LINE);}
","                       {char *yycopy=strdup(yytext); count(); printf("found %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(COMMA);}
":"                                             {char *yycopy=strdup(yytext); count(); printf("found %s at line %d\n" ,yycopy, line);
                           addsym( yycopy, block_num ); return(COLON);}

"#"                      { comment();}

{blank}                   { count();}



{invalid_keyword}    {char *yycopy=strdup(yytext); count(); printf("invalid keyword %s at line %d\n", yycopy, line);
              addsym( yycopy, block_num );}

{invalid_identifier}   {char *yycopy=strdup(yytext); count(); printf("invalid identifier %s at line %d\n", yycopy, line);
              addsym( yycopy, block_num );}


.              {char *yycopy=strdup(yytext); count(); printf("unexpected character %s at line %d\n", yycopy, line);
              addsym( yycopy, block_num );}

%%

int yywrap()
{
  return 1;
}

// void main(int argc, char *argv[]){
//   int ret_val=1;
//
//   if (argc!=2) printf("\nUsage: lexyy <input file name> \n");
//   else
//     if ((new_file=fopen(argv[1],"r"))==NULL)
//       printf("\n<%s> not found.\n",argv[1]);
//     else{
//       yyrestart(new_file);
//       while(ret_val!=0){
//         ret_val=yylex();
//       }
//       fclose(new_file);
//     }
//}

void count()
{
        int i;
        for(i=0;yytext[i]!='\0';i++)
        if(yytext[i]=='\n')
        {
                line++;
        }
}

int count_indent()
{
  int i;
  int tab_num = 0;
  for(i=0;yytext[i]=='\t';i++)
  {
    tab_num++;
  }
  return tab_num;
}


void comment()
{
  int c;
  while(c=input()!='\n' && c!=EOF)
  {

  }
  line++;
}

.y file

%{
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include <ctype.h>
    #include "y.tab.h"
    extern int yylex();
    extern FILE *yyin;
%}


%token L_THAN G_THAN EQUAL L_EQ_THAN G_EQ_THAN NEQUAL
%token ASSIGN
%token LPAREN RPAREN LSQUARE_BRACK RSQUARE_BRACK
%token END_LINE COMMA COLON
%token INDENT DEDENT


%start Program
%%

Program: Block Program
    | Empty
    ;

Empty: /* empty */
    ;

Block: Declarations
    | Subprograms
    | Sequence
    ;



%%
extern int column;

int main(int argc, char *argv[])
{
    yyin = fopen("test_code.sy", "r");
    if(yyparse()==1)
        printf("\nParsing failed\n\n");
       else
        printf("\nParsing completed successfully\n");
       fclose(yyin);
    return 0;
}

int yyerror(s)
char *s;
{
                printf("%s\n", s);
        fflush(stdout);
        return 1;
}

** РЕДАКТИРОВАНИЕ: ** файл sym_tab.h

/*#include <iostream.h>*/
#include <stdio.h>
#include <malloc.h>
#include <string.h>

#define table_size          100

extern int line=1;
extern int end_file=1;
extern int block_num=0;
extern FILE *new_file; 

typedef struct hash_sym
    {
    struct hash_sym *prev, *next;
    char *nam;
    char *str_val;
    char *id_type;
    int  id_value;
    int  block_num;
} Hashing_table; 


Hashing_table *table[table_size];

int hash_funct( char str[], int hash_size);

addsym( sym, bloc_num )
register char sym[];
int bloc_num;

{   
    int hash_val = hash_funct( sym, table_size );
    register struct hash_sym *sym_sym = table[hash_val];
    register struct hash_sym *new_sym;
    register struct hash_sym *successor;

    while ( sym_sym!=0 )
    {

        if (  strcmp( sym, table[hash_val]->nam )==0 )
        {   

            printf("the entry %s at line %d already exists at symbol table\n", sym,line);   
            return -1;
        }   

        sym_sym = sym_sym->next;
    }


    new_sym = (struct hash_sym *)
    malloc( sizeof( struct hash_sym ) );


    if ( (successor = table[hash_val]) )
    { 

        new_sym->next = successor;
        successor->prev = new_sym;
    }
    else
        new_sym->next = NULL;

    new_sym->prev = NULL;
    new_sym->nam = sym;
    new_sym->block_num = bloc_num;

    table[hash_val] = new_sym;
    return 0;
}




int hash_funct( str, hash_size )
register char str[];
int hash_size;
{
    register int hashval;
    register int i;

    hashval = 0;
    i = 0;

    while ( str[i]!='\0' )
        {
        hashval = hashval +  str[i++]*(16+i);
        /*hashval %= hash_size;*/
        }
    return (hashval %= hash_size);

}


Я ожидал, что парсер будет анализировать до конца файла. Я еще не установил распечатки в моем файле .y, поэтому я не ожидал, что там будет распечатка.

1 Ответ

1 голос
/ 07 апреля 2019

Основная проблема заключается в том, что ваша грамматика включает в себя произвольное повторение нетерминала, который может соответствовать пустой строке.

Это всегда неоднозначно, потому что невозможно различить пустую строку и две последовательные пустые строки или даже миллион последовательных пустых строк. Поэтому повторение недействительного нетерминала всегда приводит к конфликту. В большинстве случаев сгенерированный синтаксический анализатор просто неверен, но он все еще завершается. Bison разрешает конфликты сдвиг / уменьшение, выбирая сдвиг, что гарантирует, что анализатор будет проходить через ввод. По сути, он решает вопрос «сколько пустых строк» ​​с наименьшим возможным ответом, обычно «один».

Но в вашем случае повторение имеет более одной альтернативы, некоторые из которых обнуляются. Теперь у парсера проблема еще сложнее: он должен выяснить, какому нетерминалу должна соответствовать пустая строка. Это конфликт уменьшения / уменьшения, и решение бизона состоит в том, чтобы всегда выбирать нетерминал, который стоит первым в грамматике. Это будет проблемой, если правильный выбор для определенного входа - это какой-то другой нетерминал.

Вот минимальный пример того, о чем я говорю:

%%
list: %empty | unit list
unit: as | bs
as: %empty | as 'a'
bs: %empty | bs 'b'

Здесь unit может быть равно нулю или более a с или равно нулю или более b с. Поскольку ноль a s и ноль b s выглядят одинаково, синтаксический анализатор действительно не может сказать, какой из них выбрать из грамматики, поэтому он всегда выбирает ноль a s (потому что это первое в грамматике). Проблема возникает, когда вход содержит b. Поскольку синтаксический анализатор никогда не использует правило bs: %empty (фактически, bison предупреждает вас об этом), он никогда не сможет применить правило bs: bs 'b'. Поэтому, столкнувшись с b, анализатор уменьшает пустое as, превращает его в unit, добавляет его в list и затем пытается проанализировать еще один unit. Однако ничего не изменилось; токен не был прочитан, поэтому предвидение по-прежнему b. И поэтому синтаксический анализатор будет входить в бесконечный цикл, разбирая пустые unit s, содержащие пустые as снова и снова.

С продукцией list, записанной, как указано выше (рекурсивно справа), эти пустые unit необходимо добавить в стек анализатора. Таким образом, синтаксическому анализатору в конечном итоге не хватит места для его стека, и он умрет с ошибкой «исчерпана память». Если вы измените его на левую рекурсию (list: %empty | list unit), то анализатору не нужно будет использовать пространство стека, и он может продолжать анализировать пустые unit s навсегда.

Я предлагаю вам попробовать приведенный выше простой пример, используя очень полезную функцию трассировки bison (см. «Отладка вашего анализатора» в Руководстве по Bison). Это намного проще, чем заполнять файл грамматики вызовами printf, и это также намного более информативно.

Чтобы решить эту проблему, вам просто нужно, чтобы unit был непустым, что позволяет избежать проблемы «повторения пустой строки». Если каждый unit должен соответствовать чему-либо, то грамматика соответствует язык, но это делает однозначно.

...