君子抉第三天(4月20日)

本文介绍了使用Flex工具实现词法分析器的过程,包括Flex的安装配置、词法单元定义及如何生成词法分析器代码等内容。通过示例代码详细说明了如何识别关键字、标识符等元素。

      本来应该在4月20日写的,由于种种原因没有写,今天将它补起来.这是正式的按君子抉中的计划来写博客的第二天,今天搞那个垂直搜索搞了一上午,以前还感觉搞这个有点激情,现在感觉完全是一种累赘,还得写文档,麻烦啊.下午才干了点真正有点意思的东西-----flex.

   以前从来没有接触过flex,那次听兴旺说要做一个自动的词法分析器,用flex来实现,研究了半天,最后总算明白了.而且今天我才明白原来编程最痛苦的事不是代码怎么写,而是在哪里编写代码.刚开始在网上搜索了半天,都是讲解flex的程序怎么编写,就是没说,写了在哪里进行编译.最后找了半天,明白了.

   先下载flex-2.5.4a-1.exe,然后进行安装,我是安装到了D:\GnuWin32,然后在环境变量的path加上一句:  ;D:\GnuWin32\bin

再到DOS命令下进行测试安装好了没有,输入 flex -V 即可.这个是大写V.之后就是编写.l文件.编写好.l文件之后,在DOS命令行下定位到你的.l文件的目录,让后输入flex test.l 回车即可.这里test.l是你的.l文件的文件名.让后在test.l文件的同一目录就会生成一个 lex.yy.c.这个文件就可以在Visual Studio中进行编译了.下面这个是我改写的词法分析器的flex的.l文件的代码.

      

% {
#include
< stdio.h >
#include
< stdlib.h >
/* 保留字 */
#include
< string .h >
char   * key[] = { "   " , " auto " , " break " , " case " , " char " , " const " , " continue " , " default " , " do " , " double " ,
" else " , " enum " , " extern " , " float " , " for " , " goto " , " if " , " int " , " long " , " register " ,
" return " , " short " , " signed " , " sizeof " , " static " , " struct " , " switch " , " typedef " ,
" union " , " unsigned " , " void " , " volatile " , " while " }; 

int  IsKeyWord( char   * lex) ; /*  判断字符串是否是保留字  */

void  print();                             // 输出token序列;
void  main( int  argc, char * argv[]);          // 主函数;
struct  token{                             // 二元组;
       char * idproperty;     // token属性值;
       char * idname;     // 识别的token名字;
}entity[ 1000 ];      // 定义1000个这样的token,大小可改变;
char * filename;                            // 保存结果的文件名;
int  errnum = 0 ;      // 错误token的数目;
int  value;      // 属性值int型;
int  linenum = 1 ;      // 行数;
int  count = 0 ;      // token的个数;
int  flag = 0 ;
FILE
* fpin;      // 测试文件指针;
FILE * fpout;      // 结果文件指针;
% }
digit         [
0 - 9 ]
letter        [_a
- zA - Z]
number        {digit}
+
identifier    {letter}({letter}
| {digit}) *
wrongid       ({digit}
+ ){letter}({letter} | {digit}) *
newline       [\n]
whitespace    [\t]
+
allchar             [
^ 0 ] | 0
string_l            \
" {allchar}?\ "
%%
{string_l}        {value
= 6 ;print();}                                             // 字符串常量
{identifier}   {value = IsKeyWord(yytext); print();}   // 标识符---0 关键字---1
{wrongid}   {value = 7 ;print();}                                         // 错误标识符
{number}   {value = 2 ;print();}                                             // 数字常量


" ++ "           |
" -- "           |
" -> "        |
" && "      |
" || "      |
" <= "      |
" == "         |
" != "      |
" >= "      |
" >> "      |
" << "      |
" *= "      |
" /= "      |
" %= "        |
" += "      |
" -= "      |
" &= "      |
" |= "      |
" ^= "                     {value = 4 ;print();}             /* 组合运算符 */
" + "              |
" - "              |
" * "              |
" / "           |
 
" ! "      |
" % "       |
" & "       |
" | "                    {value = 3 ;print();}                                 /* 基本运算符 */
" , "              |
" ; "              |
" { "              |
" } "              |
" ( "              |
" ) "              |
" . "              |
" # "              |
" ' "               {value = 5 ;print();}                 /* 分界符 */
{newline}   {linenum
+= 1 ;}
{whitespace}   {;}
"   "     {;}
.    {value
= 7 ;print();}                  /* 其他不识别 */
%%
int  yywrap()
{  
    fclose(fpin);
    
return   1 ;
}

void  print()
{
    count
+= 1 ;
    
if (flag != 1 ){
       
if ((fpout = fopen(filename, " a " )) == NULL){
           printf(
" 无法打开文件! \n " );
           exit(
0 );
       }
    }
    
if (value <= 6 ){
       
switch (value){
             
case   0 :entity[count - 1 ].idproperty = " 标识符 " ; break ;
             
case   1 :entity[count - 1 ].idproperty = " 关键字 " ; break ;
             
case   2 :entity[count - 1 ].idproperty = " 数字常量 " ; break ;
             
case   3 :entity[count - 1 ].idproperty = " 基本运算符 " ; break ;
             
case   4 :entity[count - 1 ].idproperty = " 组合运算符 " ; break ;
             
case   5 :entity[count - 1 ].idproperty = " 分界符 " ; break ;
                 
case   6 :entity[count - 1 ].idproperty = " 字符串常量 " ; break ;
       }
       entity[count
- 1 ].idname = yytext;
       fprintf(fpout,
" %d < %s , %s > \n " ,count,entity[count - 1 ].idname,entity[count - 1 ].idproperty);
    }
else {
         errnum
+= 1 ;
         
switch (value){
               
case   8 :entity[count - 1 ].idproperty = " 错误标识符: " ; break ;
               
case   7 :entity[count - 1 ].idproperty = " 不识别: " ; break ;
         }
         entity[count
- 1 ].idname = yytext;
         fprintf(fpout,
" %d [line:%d]:%s\ " % s\ "  \n " ,count,linenum,entity[count - 1 ].idproperty,entity[count - 1 ].idname);
    }
    
if (flag != 1 )fclose(fpout);
}
/*  判断字符串是否是保留字  */

/*     如果不是就返回 0  */

int  IsKeyWord( char   * lex) 

    
int  i;
    
for ( i = 1 ;i <= 32 ;i ++ )
    { 
        
if (strcmp(lex,key[i])  ==   0
            
return   1
    } 
    
return   0
}
void  main( int  argc, char * argv[])
{
    
if (argc == 1 ){
      printf(
" please input the C program(ctrl+z to end) \n " );
      flag
= 1 ;
      fpin
= stdin;
      fpout
= stdout;
    }
    
if (argc == 2 )argv[ 2 ] = " defresult.txt " ;
    filename
= argv[ 2 ];
    
if (flag != 1 ){
       
if ((fpin = fopen(argv[ 1 ], " r " )) == NULL){
           printf(
" cannot open the file \n " );
           exit(
0 );
       }
    }
    yyin
= fpin;
    yylex();
    
if (flag != 1 ){
       
if ((fpout = fopen(filename, " a " )) == NULL){
           printf(
" cannot write the file \n " );
           exit(
0 );
       }
    }
    fprintf(fpout,
" \n " );
    fprintf(fpout,
" %d symbol(s) found. \n %d error(s) found. \n " ,count,errnum);
    fprintf(fpout,
" ======================================================================= \n " );
    
if (flag != 1 )fclose(fpout);
    yywrap();


}


 

 image004 image002

转载于:https://www.cnblogs.com/DonePuzzle/archive/2008/04/21/1164681.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值