S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

yacc学习笔记(3) 2014.04.11

Posted on 2014-04-10 09:43 S.l.e!ep.¢% 阅读(1911) 评论(0)  编辑 收藏 引用 所属分类: yacc
实现解析c++ #include 头文件的语法, 暂时没有实现 嵌套解析 #include

codegen.l
%option noyywrap
%option yylineno

%{
#include 
<stdio.h>
#include 
<stdlib.h>
#include 
"codegen.tab.h"
#define YYDEBUG 0 // 将这个变量设置为1则表示启动Yacc的调试功能

#define YYERROR_VERBOSE

extern int yylex();
extern void yyerror(char* s);

%}

%x _STATE_INCLUDE_
%x _STATE_INCLUDE_FILE_

%%

"#"[ \t]*"include" { 
        BEGIN _STATE_INCLUDE_;  
// 进入 _STATE_INCLUDE_ 状态
        return TOKEN_INCLUDE;
    }

<_STATE_INCLUDE_>[/"|<]* {
        BEGIN _STATE_INCLUDE_FILE_; // 进入 _STATE_INCLUDE_FILE_ 状态
        return *yytext; // 返回引号或尖括号
    }
    
<_STATE_INCLUDE_FILE_>[/"|>] {
        return TOKEN_INCLUDE_FILE; // 返回头文件标记
    };
    
/t/n] ; // 对于额外的空白不处理
%%
int main( int argc, char **argv )
{
    yyparse();
}
void yyerror(char *s)
{
    fprintf(stderr, 
"error: %s\n", s);
}

codegen.y
%{
#include 
<stdio.h>
#include 
<stdlib.h>
%}

%token TOKEN_INCLUDE 
%token TOKEN_INCLUDE_FILE

%%

program:
    
| program include_process
    ;

include_process:
    TOKEN_INCLUDE 
'<' TOKEN_INCLUDE_FILE '>' 
    {
        printf(
"include = [%s] \n", $3 );
    }
    
| TOKEN_INCLUDE '/"' TOKEN_INCLUDE_FILE '/"'
    {
        printf(
"include = [%s] \n", $3 );        
    }
    
%%

---------------------------------------------------
2014.04.11
上面的解析是有问题的, 当输入 #include <abc> 时,解析结果为空, 看了下书, 原因是在 返回 TOKEN_INCLUDE_FILE 标记时, 没有对 全局变量 yylval 进行赋值
yylval 是一个int 的类型, 在bison生成的代码, yylval是用 YYSTYPE 定义的,可以通过 %union 修改 YYSTYPE 的定义

修改后的代码如下:
codegen.l
%option noyywrap
%option yylineno

%{
#include 
<stdio.h>
#include 
<stdlib.h>
#include 
"codegen.tab.h"
#define YYDEBUG 1 // 将这个变量设置为1则表示启动Yacc的调试功能

#define YYERROR_VERBOSE

extern int yylex();
extern void yyerror(char* s);

%}

%x _STATE_INCLUDE_BEGIN_
%x _STATE_INCLUDE_FILE_
%x _STATE_INCLUDE_END_

%%

^"#include" { 
        BEGIN _STATE_INCLUDE_BEGIN_;
        
return TOKEN_INCLUDE;
    }

<_STATE_INCLUDE_BEGIN_>"<" {
        BEGIN _STATE_INCLUDE_FILE_;
        
return '<';
    }
    
<_STATE_INCLUDE_FILE_>[^\">]+ {
        BEGIN _STATE_INCLUDE_END_;
        yylval.m_lpStr 
= strdup(yytext);
        
return TOKEN_INCLUDE_FILE;
    }
    
<_STATE_INCLUDE_END_>">" {
        
return '>';
    }

/t/n] ; // 对于额外的空白不处理

. { printf(
"other"); }
%%
int main( int argc, char **argv )
{
    yyparse();
}
void yyerror(char *s)
{
    fprintf(stderr, 
"error: %s\n", s);
}

codegen.y
%{
#include 
<stdio.h>
#include 
<stdlib.h>

%}

%union
{
     
char* m_lpStr;
}

%token TOKEN_INCLUDE
%token TOKEN_INCLUDE_FILE

%%

program:
    
| program include_process
    ;

include_process:
    TOKEN_INCLUDE 
'<' TOKEN_INCLUDE_FILE '>'
    {
        printf(
"include = [%s] \n", yylval.m_lpStr );
        free( yylval.m_lpStr );
    }
    
%%

修改后的问题
1. 输出时多了一个空格 和 换行
2. 实现一个 include 解析, 需要这么多的独占状态么?


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理