我是靠谱客的博主 悦耳白开水,最近开发中收集的这篇文章主要介绍flex和bison实例分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

        最近在学习编译原理,利用flex和bison编写一个基于文本识别的简单计算器程序,参考《flex于bison》中内容,对程序进行一些简单的修改,加入Makefile。该计算器程序主要实现识别文本中的整数和运算符,进行加减乘除四则运算,暂不考虑括号对运算顺序的影响。
        flex用于词法分析器的构建,bison用于语法分析器构建,两者可以结合使用,利用bison生成源程序可以直接调用flex生成源程序中yylex()函数,提取标准输入文本中的目标字符,虽然main函数可以放到flex或bison的源码文件的用户自定义部分,但是不便于阅读和理解。因此将main函数单独放到一个cpp文件中,调用bison源码文件中的yyparse()函数对输入内容进行解析和处理。将计算器的运算实现放到bison源码的规则部分。
       创建test.l文件,编写词法分析规则(数字和符号识别)

%{
    #include <stdio.h>
    #include "test_yacc.h" 
    //因为使用了bison在test_yacc.h中自动生成的token枚举

    extern int yylval; 
    //yylval定义在bison库中
%}

number [0-9]

%%
{number}+ {
    yylval = atoi(yytext);
    printf("number: %d  ", yylval);
    return INT;
}

"+" {
    printf("operator: +  ");
    return ADD; 
}

"-" {
    printf("operator: -  ");
    return SUB;
}

"*" {
    printf("operator: *  ");
    return MUL;
}

"/" {
    printf("operator: /  ");
    return DIV;
}

n { return EOL; }

[ t] {}

. { //该条规则匹配除以上字符外的剩余字符,并且报错
    printf("error: input illegal character '%s'.n", yytext);
}
%%

void yyerror(const char *msg) 
//该函数的重写可以放在任意位置,bison的yyparse()会调用该函数,需在.y文件中声明此函数
//传参必须为const,不然编译会报warning
{
    fprintf(stderr, "error: %s.n", msg);
}

        创建test.y文件,编写语法分析规则(计算器的运算处理),cal为创建的空规则,专门用于判断是否有换行,如果有换行,完成一次cal的规约,exp属性栈弹出,即exp清零。根据BNF表示方法,将首处理符号INT放在最底层规则,其次优先匹配乘除法,在处理乘除法之后再匹配加减法。

%{
    #include <stdio.h>

    extern int yylex();
    extern void yyerror(const char *);
%}

%token INT
%token ADD SUB MUL DIV
%token EOL
%%
cal : 
    | cal exp EOL { printf("n<archerfoo> caculation result: %dn", $2); }
    ;

exp : factor
    | exp ADD factor { $$ = $1 + $3; } 
    | exp SUB factor { $$ = $1 - $3; } 
    ;

factor : term
    | factor MUL term { $$ = $1 * $3; } 
    | factor DIV term { $$ = $1 / $3; } 
    ;

term : INT
    ;
%%

        创建testMain.cpp,编写main函数内容:

#include <stdio.h>

//extern int yylex();
extern int yyparse();

int main(int argc, char ** args) 
{
    //yylex(); 
    yyparse(); //调用bison的yyparse()函数

    return 0;
}

        编写编译Makefile脚本

ECHO = echo
CXX  = g++

TARGET = ./testDemo

LIBS   = -lfl

CFLAGS = -Wall
CFLAGS += -std=c++11

OBJECTS =  testMain.o 
OBJECTS += test_yacc.o
OBJECTS += test_lex.o

$(TARGET) : $(OBJECTS)
    $(CXX) -o $(TARGET) $(OBJECTS) $(LIBS) $(CFLAGS) 

.cpp.o :
    $(CXX) -o $@ -c $<

#生成test_yacc.cpp、test_yacc.h
#test_yacc.h会生成token的相关枚举
test_yacc.cpp : test.y
    bison -d $< -b test_yacc
    mv test_yacc.tab.c test_yacc.cpp
    mv test_yacc.tab.h test_yacc.h

#生成test_lex.cpp
test_lex.cpp : test.l
    flex -o $@ $<

.PHONY : clean

clean:
    rm $(OBJECTS) $(TARGET) test_yacc.h test_yacc.cpp test_lex.cpp

        编译:

     yylex()返回记号token标志,标志0-255被保留作为字符值,可以自己定义token标志的值,一般由bison产生的token标志默认从258开始。本例中,由bison生成的test_yacc.h文件,其中token枚举定义:

       调试结果:

最后

以上就是悦耳白开水为你收集整理的flex和bison实例分析的全部内容,希望文章能够帮你解决flex和bison实例分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(104)

评论列表共有 0 条评论

立即
投稿
返回
顶部