lex && yacc

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_35390390/article/details/74453485


举个栗子:

if(a > b && c < d)
{
}

假如需要分析上面的if语句

lex的模式规则定义如下:

"if"    {return IF;}
"("    {return BOL;}
")"    {return BOR;}
"&&"    {return AND;}
"{"    {return BEL;}
"}"    {return BER;}
">"    {return MOT;}
"<"    {return LET;}
[a-zA-Z]*    {return VALSTR;}
(\n|\r)+    {}
其中,BOL BOR等是一些枚举值

则,lex打标记之后,变成如下形式:

IF BOL VALSTR MOT VALSTR AND VALSTR LET VALSTR BOR BEL BER
lex是对输入文本进行模式匹配的过程


之后yacc对标记进行语法分析

yacc的语法规则定义如下:

root: conditon trunk {do something...}

condition: IF BOL expr BOR {do something...}

trunk: BEL  BER | BEL action BER {do something...}

expr: BOL expr BOR{} | expr AND expr{} | expr MOT expr{} | expr LET expr{} | VALSTR{}

语法分析会按照设定的语法规则,生成一棵语法树,并且从底向上执行每个规则对应的动作

可以看到,上面的语法规则和lex分析的结果一一对应,而规则对应的动作则可以自定义,这样就可以实现自定义的语法了

lex:

    词法分析器,和c是强耦合
    简单地讲,lex做的是一个字符串匹配的工作,它从待匹配的文本字符串中寻找预设的表达式,如果寻找到一个特定的表达式,则执行相应的动作
    支持的表达式类似正则表达式
    
    使用方式:
    1 按照lex的规则,指定表达式及其相应的动作
    2 根据上一步配置的表达式和动作,生成扫描器的c代码
    
    lex的规则配置:
    共分为三个段
    1 c和lex的全局声明
        这部分放置c变量声明、include文件、lex的标记声明等,语法如
        %{
        int wordCount = 0;
        %}
        chars [A-za-z\_\'\.\"]
        numbers ([0-9])+
        delim [" "\n\t]
        whitespace {delim}+
        words {chars}+
        %%
        其中,c变量声明、include文件放在%{%}中, %%是段的分隔符,表示该段的结束和下一段的开始
        如上chars、numbers 等被声明为一个标记,其后是对应的匹配表达式。即当匹配上相应表达式的时候,该文本会被打上对应的标记
        
    2 模式
        语法如下:
        {words} { wordCount++; /* increase the word count by one*/ }
        {whitespace} { /* do nothing*/ }
        {numbers} { /* one may want to add some processing here*/ }
        %%
        如上定义的规则,遇到words的时候,wordCount自增,遇到空格,则跳过,其他未定义
        冲突解决规则:
        1) 总是选择最长的前缀
        2) 如果最长的可能前缀与多个模式匹配,总是选择Lex中先被列出的模式。
        
    3 补充的c函数,此部分可以省略
        void main()
        {
        yylex(); /* start the
        analysis*/
        printf(" No of words:
        %d\n", wordCount);
        }
        int yywrap()
        {
        return 1;
        }
    

yacc:

    语法分析器
    
    终端和非终端符号
    终端符号 : 代表一类在语法结构上等效的标记。 终端符号有三种类型:
    命名标记: 这些由 %token 标识符来定义。 按照惯例,它们都是大写。
    字符标记 : 字符常量的写法与 C 相同。例如, -- 就是一个字符标记。
    字符串标记 : 写法与 C 的字符串常量相同。例如,"<<" 就是一个字符串标记。
    lexer 返回命名标记。
    非终端符号 : 是一组非终端符号和终端符号组成的符号。 按照惯例,它们都是小写。 在例子中,file 是一个非终端标记而 NAME 是一个终端标记。
    
    规则编写也分为三部分
    1 声明
    2 语法规则
    3 c代码(可省略)

lex 和 yacc一起使用

    lex和yacc共享标记的声明
    lex来做词法分析,根据配置的规则,返回对应的标记
    yacc 根据lex返回的标记定义语法规则,并根据规则进行相应的动作
    
参考https://www.ibm.com/developerworks/cn/linux/sdk/lex

猜你喜欢

转载自blog.csdn.net/weixin_35390390/article/details/74453485