使用flex和bison解析文件时出现语法错误

时间:2016-02-11 09:06:04

标签: parsing block flex-lexer bisonc++

我正在解析以下文件:

BEGIN BLOCK BLK_ROWDEC            
        NAME                          cell_rowdec
        SIZE                          UNI_rowdecSize
        ITERATE                       itr_rows
        DIRECTION                     lgDir_rowdec
        STRAP                         STRD1,STRD3,STRD2
        WRAP                          WRD1
        VIA                           VIAB,VIAC,VIAD
ENDS BLK_ROWDEC

我的flex和bison文件如下:

lexa.l

%{
#include <iostream>
#include <stdio.h>
const char s[2] = " ";
#include "yacc.tab.h"
char *token;
#define YY_DECL extern "C" int yylex()
int line_num = 1;



using namespace std;
%}

DOT             "."
COLON           ":"
SEMICOLON       ";"
COMMA           ","
ANGLE_LEFT      "<"
ANGLE_RIGHT     ">"
AT              "@"
EQUAL           "="
SQUARE_OPEN     "["
SQUARE_CLOSE    [^\\]"]"
OPENBRACE       "\("
CLOSEBRACE      "\)"
QUOTE           "\""
QUOTE_OPEN      "\""
QUOTE_CLOSE     [^\\]"\""
SPACE           " "
TAB             "\t"
CRLF            "\r\n"
QUOTED_PAIR     "\\"[^\r\n]
DIGIT           [0-9]
ALPHA           [a-zA-Z]
QTEXT           [0-9a-zA-Z!#$%&'()*+,\-.\/:;<=>?@\[\]^_`{|}~]


%%



[ \t]         ;


^BEGIN(.*)\r?\n+\s*BEGIN(.*)     {   printf("\nError : two continous BEGIN is not allowed : "); }

^ENDS(.*)\r?\n+\s*ENDS(.*)   {   printf("\nError : two continous END is not allowed : \n"); }




NAME          {  yylval.sval = strdup(yytext);
    return TOK_NAME; }

SIZE          { yylval.sval = strdup(yytext);
      return TOK_SIZE; }

ITERATE       { yylval.sval = strdup(yytext);
       return TOK_ITERATE; }

DIRECTION   { yylval.sval = strdup(yytext);
      return TOK_DIRECTION; }

STRAP       { yylval.sval = strdup(yytext);
      return TOK_STRAP; }

WRAP        { yylval.sval = strdup(yytext);
      return TOK_WRAP; }

VIA     { yylval.sval = strdup(yytext);
      return TOK_VIA; }

ENDS        { yylval.sval = strdup(yytext);
      return TOK_END; }

BEGIN       { yylval.sval = strdup(yytext);
      return TOK_BEGIN; }

BLOCK       { yylval.sval = strdup(yytext);
      return TOK_BLOCK; }




[a-zA-Z0-9_,]+    { yylval.sval = strdup(yytext);
      return TOK_STRING; }


{SPACE}*          { return TOK_SPACE; }




^ENDS(.*)$        {}


^{CRLF}                         { return TOK_EMPTY_LINE; }
{CRLF}                          {}
.                               {}/* ignore unknown chars */
\n                      { ++line_num; return ENDL; }

yacca.y

%{
#include <cstdio> 
#include <cstring>
#include <iostream>
#include <stdio.h>

#define YYDEBUG 1

using namespace std;

extern "C" int yylex();
extern "C" FILE *yyin;
extern int line_num;


void yyerror(const char* s);
%}

// Symbols.
%union
{
    char* sval;
};

%token <sval> TOK_NAME
%token <sval> TOK_SIZE
%token <sval> TOK_STRING
%token <sval> TOK_ITERATE
%token <sval> TOK_DIRECTION
%token <sval> TOK_STRAP
%token <sval> TOK_WRAP
%token <sval> TOK_VIA
%token <sval> TOK_EMPTY_LINE 
%token <sval> TOK_BLOCK
%token <sval> TOK_LINE
%token <sval> TOK_BEGIN
%token <sval> TOK_END
%token TOK_SPACE
%token END ENDL



%%

language : program ;


program : block
| program block
;

block   : TOK_BEGIN TOK_BLOCK TOK_SPACE TOK_STRING blockcontents TOK_END TOK_SPACE TOK_STRING 
  {
    cout << endl << "SHAILAVI" << $4 << " ";

  }
;


blockcontents : item
      | blockcontents item
      ;


item    :   TOK_SPACE TOK_NAME TOK_SPACE TOK_STRING         
    { 
        cout << endl << "Value:" << $2 << "->" << $4 << "  "; 
    }
    | TOK_SPACE TOK_SIZE TOK_SPACE TOK_STRING        { cout << $2 << "->" << $4 << "  "; }
    | TOK_SPACE TOK_ITERATE TOK_SPACE TOK_STRING     { cout << $2 << "->" << $4 << "  ";  }
    | TOK_SPACE TOK_DIRECTION TOK_SPACE TOK_STRING   { cout << $2 << "->" << $4 << "  " << endl; }
    | TOK_SPACE TOK_STRAP TOK_SPACE TOK_STRING       { cout << "ref:" << $2 << "->" << $4 << "  "; }
    | TOK_SPACE TOK_WRAP TOK_SPACE TOK_STRING    { cout << $2 << "->" << $4 << "  "; }
    | TOK_SPACE TOK_VIA TOK_SPACE TOK_STRING     { cout << $2 << "->" << $4 << "  " << endl; }
    ;



%%



int main(void) {
    FILE * pt = fopen("file", "r" );
    if(!pt)
    {
    cout << "Bad Input.Noexistant file" << endl;
    return -1;
    }
    yyin = pt;
    do
    {
    yydebug = 1;
        yyparse();
    }while (!feof(yyin));      
}
void yyerror(const char *s) {
    cout << "parse error on line " << line_num << "!  Message: " << s << endl;
    exit(-1);
}


#include "lex.yy.c"

编译步骤:

flex lexa.l
bison -d yacca.y
g++ yacca.tab.c -lfl -o scanner.exe

执行时,syntax error靠近 blockcontents

请帮我识别我所犯的错误。

非常感谢你。

1 个答案:

答案 0 :(得分:2)

我花了一段时间,但我发现了这个缺陷。

在词法分析器中,您跳过所有标签和空白序列(第一条规则)。 但是你的解析器时不时会想到空白区域。因此语法错误。

由于你不对白色空间做任何事情,只需在词法分析器中吃它们(正如你现在已经做过的那样,但最好也消除{SPACE} *规则)并消除TOK_SPACE解析器。

----编辑提供一些提示----

我追踪错误的方法是:

  1. 让词法分子变得冗长 我添加了(省略了哈希标记;由于某种原因,它会混淆渲染器)
  2. 
             #ifdef DEBUG
             #define RETURN(x)       cerr << "\n--> found " << #x << "\n"; return x;
             #else
             #define RETURN(x)       return x;
             #endif
    

    并取代所有&#34;返回一些东西&#34;通过RETURN(某事)

    1. 我分别编译bison / flex文件并在之后链接
    2. 
          flex lexa.l && \
          bison -d yacca.y && \
          g++ -c -DDEBUG -I . lex.yy.c && \
          g++ -c -I . yacca.tab.c && \
          g++ lex.yy.o yacca.tab.o -o scanner
      

      (在这里使用linux)

      1. 按要求提供工作示例
      2. 
            %{
            #include <cstdio>
            #include <cstring>
            #include <iostream>
            #include <stdio.h>
        
            #define YYDEBUG 1
        
            using namespace std;
        
            extern "C" int yylex();
            extern "C" FILE *yyin;
            extern int line_num;
        
        
            void yyerror(const char* s);
            %}
        
            // Symbols.
            %union
            {
                char* sval;
            };
        
            %token  TOK_NAME
            %token  TOK_SIZE
            %token  TOK_STRING
            %token  TOK_ITERATE
            %token  TOK_DIRECTION
            %token  TOK_STRAP
            %token  TOK_WRAP
            %token  TOK_VIA
            %token  TOK_EMPTY_LINE
            %token  TOK_BLOCK
            %token  TOK_LINE
            %token  TOK_BEGIN
            %token  TOK_END
            %token END ENDL
        
            %%
        
            language : program ;
        
        
            program : block
            | program block
            ;
        
            block   : TOK_BEGIN TOK_BLOCK TOK_STRING blockcontents TOK_END TOK_STRING 
              {
                cout << endl << "SHAILAVI" << $3 << " ";
        
              }
            ;
        
        
            blockcontents : item
                  | blockcontents item
                  ;
        
        
            item    :   TOK_NAME TOK_STRING         { cout << endl << "Value:" << $1 << "->" << $2 << "  "; }
                | TOK_SIZE TOK_STRING        { cout << $1 << "->" << $2 " << $2 " << $2 " << $2 << "  "; }
                | TOK_WRAP TOK_STRING    { cout << $1 << "->" << $2 << "  "; }
                | TOK_VIA TOK_STRING     { cout << $1 << "->" << $2 << "  " << endl; }
                ;
        
            %%
        
            int main(void) {
                FILE * pt = fopen("./input", "r" );
                if(!pt)
                {
                cout << "Bad Input.Nonexistent file" << endl;
                return -1;
                }
                yyin = pt;
                do
                {
                yydebug = 1;
                    yyparse();
                }while (!feof(yyin));
            }
            void yyerror(const char *s) {
                cout << "parse error on line " << line_num << "!  Message: " << s << endl;
                exit(-1);
            }
            extern "C" int yywrap()
            {
                    return (1 == 1);
            }
        

        和词法分析器

        
            %{
            #include 
            #include 
            const char s[2] = " ";
            #include "yacca.tab.h"
            char *token;
            #define YY_DECL extern "C" int yylex()
            int line_num = 1;
        
            #ifdef DEBUG
            #define RETURN(x)       cerr << "\n--> found " << #x << "\n"; return x;
            #else
            #define RETURN(x)       return x;
            #endif
        
        
            using namespace std;
            %}
        
            DOT             "."
            COLON           ":"
            SEMICOLON       ";"
            COMMA           ","
            ANGLE_LEFT      ""
            AT              "@"
            EQUAL           "="
            SQUARE_OPEN     "["
            SQUARE_CLOSE    [^\\]"]"
            OPENBRACE       "\("
            CLOSEBRACE      "\)"
            QUOTE           "\""
            QUOTE_OPEN      "\""
            QUOTE_CLOSE     [^\\]"\""
            SPACE           " "
            TAB             "\t"
            CRLF            "\r\n"
            QUOTED_PAIR     "\\"[^\r\n]
            DIGIT           [0-9]
            ALPHA           [a-zA-Z]
            QTEXT           [0-9a-zA-Z!#$%&'()*+,\-.\/:;?@\[\]^_`{|}~]
        
        
            /* [ \t]         ; */
            %%
        
            ^BEGIN(.*)\r?\n+\s*BEGIN(.*)     {   printf("\nError : two continous BEGIN is not allowed : "); }
        
            ^ENDS(.*)\r?\n+\s*ENDS(.*)   {   printf("\nError : two continous END is not allowed : \n"); }
        
        
        
        
            NAME          {  yylval.sval = strdup(yytext);
                RETURN(TOK_NAME); }
        
            SIZE          { yylval.sval = strdup(yytext);
                  RETURN(TOK_SIZE); }
        
            ITERATE       { yylval.sval = strdup(yytext);
                   RETURN(TOK_ITERATE); }
        
            DIRECTION   { yylval.sval = strdup(yytext);
                  RETURN(TOK_DIRECTION); }
        
            STRAP       { yylval.sval = strdup(yytext);
                  RETURN(TOK_STRAP); }
        
            WRAP        { yylval.sval = strdup(yytext);
                  RETURN(TOK_WRAP); }
        
            VIA     { yylval.sval = strdup(yytext);
                  RETURN(TOK_VIA); }
        
            ENDS        { yylval.sval = strdup(yytext);
                  RETURN(TOK_END); }
        
            BEGIN       { yylval.sval = strdup(yytext);
                  RETURN(TOK_BEGIN); }
        
            BLOCK       { yylval.sval = strdup(yytext);
                  RETURN(TOK_BLOCK); }
        
        
            [a-zA-Z0-9_,]+    { yylval.sval = strdup(yytext); RETURN(TOK_STRING); }
        
            ^ENDS(.*)$        {}
        
        
            ^{CRLF}                         { RETURN(TOK_EMPTY_LINE); }
            {CRLF}                          {}
            .                               {}/* ignore unknown chars */
            \n                      { ++line_num; /* RETURN(ENDL); */ }
        

        只留下一个问题。它并不像EOF那样。我将此作为练习。