【问题标题】:Parser using flex and Bison使用 flex 和 Bison 的解析器
【发布时间】:2017-11-20 03:35:04
【问题描述】:

我正在使用 flex 和 bison 来实现解析器。我遇到的一个问题是如何将单独的 flex 文件的标记提供给解析器。当我尝试编译我的parser.tab.c 时,它抱怨"undefined reference to yylex"。 然后我尝试在编译时设置-d选项,并将头文件包含到flex文件中。

我只是想知道使用flex和bison的正确步骤(配合相关命令编译运行)我用的是gcc编译器。

非常感谢

/* Token Scanner for C- language */

%{

#include <stdio.h>
#include <stdlib.h>
#include "parser.tab.h"
extern YYSTYPE yylval;



%}



digit                [0-9]
letter               [a-zA-Z]
NUM              {digit}+
ID               {letter}+
KEY_WORD             else|if|int|return|void|while
PLUS_OPERATOR            "+"
MINUS_OPERATOR               "-"
MUL_OPERATOR                 "*"
DIV_OPERATOR                 "/"
LESS_THAN_OPERATOR           "<"
LESS_THAN_OR_EQUAL_OPER      "<="
GREATER_THAN_OPERATOR            ">"
GREATER_THAN_OR_EQUAL_OPERATOR   ">="
EQUAL_OPERATOR           "="
OBJ_EQUAL_OPERATOR           "=="
NOT_EQUAL_OPERATOR           "!="
COMMA_SYMBOL             ","
SEMI_COLON_SYMBOL        ";"
LEFT_BRAC_SYMBOL         "("
RIGHT_BRAC-SYMBOL        ")"
LEFT_SQUARE_BRAC_SYMBOL          "["
RIGHT_SQUARE_BRAC_SYMBOL     "]"
LEFT_CURLY_BRAC_SYMBOL       "{"
RIGHT_CURLY_BRAC_SYMBOL      "}"
LEFT_COMMENT             "/*"
RIGHT_COMMENT            "*/"
ELSE                "else"
IF              "if"
INT             "int"
RETURN              "return"
VOID                "void"
WHILE               "while"

SYMBOL               "+"|"-"|"*"|"/"|"<"|"<="|">"|">="|"=="|"!="|"="|";"|","|"("|")"|"{"|"}"|"["|"]"|"/*"|"*/"      

WHITESPACE                [ \t\n]+
COMMENT               "/*"(.)*({WHITESPACE})*(.)*"*/"

ERROR1                {NUM}(({ID}|{KEY_WORD})|{NUM})+
ERROR2                {ID}(({NUM}|{KEY_WORD})|{ID})+
ERROR3                {KEY_WORD}(({ID}|{NUM})|{KEY_WORD})+  

ERROR                 ERROR1|ERROR2|ERROR3


%%


{NUM}            {
                return NUM;
                }

{ELSE}               {
                return ELSE;
                        }

{IF}             {
                return IF;
                        }

{INT}            {
                return INT;
                        }

{RETURN}             {
                return RETURN;
                        }

{VOID}               {
                return VOID;
                        }

{WHILE}              {
                return WHILE;
                        }


{ID}                {
                return ID;
                }

{PLUS_OPERATOR}      {
                return PLUS_OPERATOR;
                     }

{MINUS_OPERATOR}    {
                return MINUS_OPERATOR;
                     }

{MUL_OPERATOR}          {
                return MUL_OPERATOR;
                        }
{DIV_OPERATOR}          {
                return DIV_OPERATOR;
                        }
{LESS_THAN_OPERATOR}    {
                return LESS_THAN_OPERATOR;
                        }
{LESS_THAN_OR_EQUAL_OPER}   {
                return LESS_THAN_OR_EQUAL_OPER;
                        }

{GREATER_THAN_OPERATOR}  {
                return GREATER_THAN_OPERATOR;
                        }

{GREATER_THAN_OR_EQUAL_OPERATOR}   {
                return GREATER_THAN_OR_EQUAL_OPERATOR;
                        }
{EQUAL_OPERATOR}        {
                return EQUAL_OPERATOR;
                        }
{OBJ_EQUAL_OPERATOR}    {
                return NOT_EQUAL_OPERATOR;
                        }
{NOT_EQUAL_OPERATOR}    {
                return NOT_EQUAL_OPERATOR;
                        }
{COMMA_SYMBOL}  {
                return COMMA_SYMBOL;
                        }
{SEMI_COLON_SYMBOL}   {
                return SEMI_COLON_SYMBOL;
                        }

{LEFT_BRAC_SYMBOL}   {
                return LEFT_BRAC_SYMBOL;
                        }
{RIGHT_BRAC-SYMBOL}  {
                return RIGHT_BRAC_SYMBOL;
                        }

{LEFT_SQUARE_BRAC_SYMBOL}   {
                return LEFT_SQUARE_BRAC_SYMBOL;
                        }
{RIGHT_SQUARE_BRAC_SYMBOL}  {
                return RIGHT_SQUARE_BRAC_SYMBOL;
                        }
{LEFT_CURLY_BRAC_SYMBOL}   {
                return LEFT_CURLY_BRAC_SYMBOL;
                                }
{RIGHT_CURLY_BRAC_SYMBOL}  {
                return RIGHT_CURLY_BRAC_SYMBOL;
                                }

{LEFT_COMMENT}  {
                return LEFT_COMMENT;
                                }

{RIGHT_COMMENT}  {
                return RIGHT_COMMENT;
                                }
 {WHITESPACE}   {

                                }

{ERROR}          {

                                }              
%%

main( argc, argv )
int argc;
char **argv;
    {
    ++argv, --argc;  /* skip over program name */
    if ( argc > 0 )
            yyin = fopen( argv[0], "r" );
    else
            yyin = stdin;

    yylex();
    }


int yywrap(void){return 1;}

解析器:

%{
#include <stdio.h>
#include <ctype.h>
#define YYDEBUG 1

%}

%token ID NUM PLUS_OPERATOR MINUS_OPERATOR MUL_OPERATOR DIV_OPERATOR LESS_THAN_OPERATOR LESS_THAN_OR_EQUAL_OPER GREATER_THAN_OPERATOR GREATER_THAN_OR_EQUAL_OPERATOR EQUAL_OPERATOR OBJ_EQUAL_OPERATOR           NOT_EQUAL_OPERATOR COMMA_SYMBOL SEMI_COLON_SYMBOL LEFT_BRAC_SYMBOL RIGHT_BRAC_SYMBOL LEFT_SQUARE_BRAC_SYMBOL RIGHT_SQUARE_BRAC_SYMBOL LEFT_CURLY_BRAC_SYMBOL RIGHT_CURLY_BRAC_SYMBOL           LEFT_COMMENT RIGHT_COMMENT ELSE IF INT RETURN VOID WHILE 

%expect 1


%%


program: declaration_list
;

declaration_list: declaration_list declaration
    | declaration                   { printf("njuwandusanduansduasdsdsdsa"); }
;

declaration : var_declaration 
    | fun_declaration               { printf("njuwandusanduansduasdsdsdsa");}
;

var_declaration : type_specifier ID SEMI_COLON_SYMBOL
    | type_specifier ID LEFT_SQUARE_BRAC_SYMBOL NUM RIGHT_SQUARE_BRAC_SYMBOL COMMA_SYMBOL       { printf("njuwandusanduansduasdsdsdsa"); }
;

type_specifier : INT
    | VOID                  { printf("njuwandusanduansduasdsdsdsa");}
;

fun_declaration : type_specifier ID LEFT_BRAC_SYMBOL params RIGHT_BRAC_SYMBOL compound_stmt
;

params :  param_list 
    | VOID
;

param_list : param_list COMMA_SYMBOL param
    | param
;

param : type_specifier ID 
    | type_specifier ID LEFT_SQUARE_BRAC_SYMBOL RIGHT_SQUARE_BRAC_SYMBOL
;
compound_stmt : LEFT_CURLY_BRAC_SYMBOL local_declarations statement_list RIGHT_CURLY_BRAC_SYMBOL
;

local_declarations : local_declarations var_declaration
    | /* empty */
;

statement_list : statement_list statement
    |/* empty */
;

statement : expression_stmt
    | compound_stmt
    | selection_stmt
    | iteration_stmt
    | return_stmt
;

expression_stmt : expression SEMI_COLON_SYMBOL
    | SEMI_COLON_SYMBOL
;

selection_stmt : IF LEFT_BRAC_SYMBOL  expression RIGHT_BRAC_SYMBOL  statement
    | IF LEFT_BRAC_SYMBOL  expression RIGHT_BRAC_SYMBOL statement ELSE statement
;

iteration_stmt : WHILE LEFT_BRAC_SYMBOL  expression RIGHT_BRAC_SYMBOL  statement
;

return_stmt : RETURN SEMI_COLON_SYMBOL
    | RETURN expression SEMI_COLON_SYMBOL
;

expression:  var EQUAL_OPERATOR expression 
    | simple_expression
;

var : ID
     | ID LEFT_SQUARE_BRAC_SYMBOL expression RIGHT_SQUARE_BRAC_SYMBOL
;

simple_expression : additive_expression relop additive_expression
    | additive_expression
;

relop : LESS_THAN_OR_EQUAL_OPER
    | LESS_THAN_OPERATOR
    | GREATER_THAN_OPERATOR
    | GREATER_THAN_OR_EQUAL_OPERATOR
    | OBJ_EQUAL_OPERATOR 
    | NOT_EQUAL_OPERATOR
;

additive_expression : additive_expression addop term
        | term          
;

addop : PLUS_OPERATOR
    | MINUS_OPERATOR    { printf("njuwandusanduansduasdsdsdsa"); }
;

term : term mulop factor     { $$ = $1 + $3; }
    | factor
;

mulop : MUL_OPERATOR
    | DIV_OPERATOR
;

factor : LEFT_BRAC_SYMBOL  expression RIGHT_BRAC_SYMBOL 
    | var
    | call
    | NUM
;

call : ID LEFT_BRAC_SYMBOL  args RIGHT_BRAC_SYMBOL 
;

args : arg_list
    |/* empty */
;

arg_list : arg_list COMMA_SYMBOL expression
    | expression

;



%%

main()
{

extern int yydebug;
yydebug=1;
return yyparse();
}


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

【问题讨论】:

    标签: bison


    【解决方案1】:

    "yylex 是词法分析器函数,它从输入流中识别标记并将它们返回给解析器。Bison 不会自动创建此函数,因此您必须编写它以便 yyparse 可以调用。”

    来源:文档...

    所以你必须编写 yylex 函数,以便它调用 flex 函数。

    Flex 和 Bison 都提供了很好的完整示例和完美的文档:

    【讨论】:

      【解决方案2】:

      yylex 是通过flex 运行弹性文件后定义的函数。来自 GCC 的“对 yylex 的未定义引用”告诉您链接器找不到 yylex 的定义。您的问题是您正在尝试生成一个没有所有部分的可执行映像。

      例如,假设您有 3 个文件,main.c、flex.l、parser.y。你可以这样做来编译它们。

      flex flex.l
      bison -d parser.y
      gcc main.c parser.tab.c lex.yy.c -o myEXE
      

      这将产生一个可执行文件。但是,假设您有很多很多文件,并且一直这样做会很慢。你会想要一块一块地编译。

      flex flex.l
      gcc -c lex.yy.c -o lex.o
      bison -d parser.y
      gcc -c parser.tab.c -o parser.o
      gcc -c main.c -o main.o
      gcc main.o parser.o lex.o
      

      -c 选项告诉 gcc 编译并生成一个目标文件(源代码->编译成汇编->汇编汇编)。它不做任何链接。

      现在开始讨论如何使用make,你可以在 google 上找到几个很好的教程。

      【讨论】:

        【解决方案3】:

        如果您只包含 flex.l 和 parser.y 等 2 个文件并尝试编译意味着请像这样编译

        gcc -o myexe parser.tab.c lex.yy.c -lfl

        lfl 是用于词法分析器的链接文件库。如果您缺少包含 -lfl 意味着您收到错误:未定义对 yylex 的引用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-04-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多