Scaner

扫描器实验报告

by Sandy & Sabrina

目录

扫描器实验报告... 1

一.        实验目标... 2

二.        实验要求... 2

三.        实验分析... 2

1.       正则表达式... 2

2.       NFA. 3

3.       状态转换表... 3

4.       DFA. 4

四.        实验步骤... 4

1.      为了便于测试,首先编写扫描器的输入输出部分。... 4

2.      添加了一部分TokenType和关键字。... 5

3.      扫描器的核心代码中,表驱动的实现。... 6

4.      检查错误代码如下: 6

五.        运行界面... 7

1.      正常运行界面... 7

2.      丢失右半边 ’}’ 时,显示ERROE. 8

3.      丢失右半边引号时,显示ERROR. 8

4.      检测到错误字符时,显示ERROR. 8

六.        备注说明... 8

1.       测试代码... 8

2.       关于TokenType. 9

3.       使用语言和编译环境说明... 9

 

一.  实验目标

设计一个简单的扫描器,要求实现以下目标:

  1. 输入为一个源代码文件,要求输出为token数据流。
  2. 扫描器要实现最长可能的匹配。例如:一个字符串‘:=’应该被识别为‘ass-symbol’而不是‘:’和‘=’。
  3. token要表示为(Kind,Value)的形式。我们用一下的标识符来表示   不同类型的token。

KEY表示关键字

SYM表示特殊符号

ID表示识别码

NUM表示数字串

STR表示字符串

  1. 检查词汇错误:给出意义错误消息以及错误发生的行数。词汇错误的种类有:

⑴ 非法字符,也就是说,扫描器可以识别一个不在TINY+字母表中的字符。例如$就是一个非法字符。

⑵ 一个字符串的右半边引号丢失,例如 ‘scanner。

⑶ 一个评论的右半边大括号丢失,例如{this is an example。

二.  实验要求

1. 用C或C++编写程序。

2. 在8个学时内完成该实验,提交报告和源程序。

三.  实验分析

1. 正则表达式

ID=letter (letter | digit)*

NUM=digitdigit*

STRING=' any character except '  

letter=a|…|z|A|…|Z

digit=0|…|9

 

2.NFA

ID:

 

                                  Figure 3-1 ID的NFA

NUM:

 

                                Figure 3-2 NUM的NFA

STRING:

 

                                Figure 3-3STRING的NFA

 

                          Figure 3-4 部分符号的NFA

3. 状态转换表

blank

digit

letter

{

}

;

:

+

-

*

/

(

)

=

,

EOF

Other

START

START

INNUM

INID

INCOMMENT

ERROR

DONE

INASSIGN

DONE

DONE

DONE

DONE

DONE

DONE

INGREATER

INSMAUER

DONE

DONE

INSTRING

DONE

ERROR

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

START

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

INCOMMENT

ERROR

INCOMMENT

INNUM

DONE

INNUM

ERROR

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

INID

DONE

INID

INID

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

INASSIGN

ERROR

ERROR

ERROR

ERROR

ERROR

ERROR

ERROR

ERROR

ERROR

ERROR

ERROR

ERROR

ERROR

ERROR

ERROR

DONE

ERROR

ERROR

ERROR

ERROR

INGREATER

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

INSMALLER

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

DONE

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

INSTRING

DONE

ERROR

INSTRING

DONE

ERROR

 

4.DFA

 

Figure 3-5 所有字符的DFA

PS: 1、上图中三个ERROR为同一个,由于不方便才画成三个。

              2、表示该状态转换不需要保存当前字符。

四.  实验步骤

1.      为了便于测试,首先编写扫描器的输入输出部分。 

输入输出部分主要沿用UTIL.h和UTIL.C两个文件,并做了点修改。

在void printToken( TokenTypetoken, const char*tokenString )中添加了新的关键字、特殊字符和STR的输出。

MAIN文件主要沿用书上的代码,只是将其中的一部分BOOL值作了修改。

/* set NO_PARSE to TRUE to get a scanner-only compiler */

#define NO_PARSE TRUE//FALSE

/* set NO_ANALYZE to TRUE to get a parser-only compiler */

#define NO_ANALYZE TRUE//FALSE

/* set NO_CODE to TRUE to get a compiler that does not

 * generate code

 */

#define NO_CODE TRUE//FALSE

int EchoSource = TRUE;//FALSE;

intTraceScan = TRUE;//FALSE;

同时,在MAIN文件中修改了如下一段代码: 

Debug时

Release版

// char pgm[120]; /* source code file name */

/*

  if (argc != 2)

    { fprintf(stderr,”usage: %s <filename>\n”,argv[0]);

      exit(1);

    }

  strcpy(pgm,argv[1]) ;

  if (strchr (pgm, ‘.’) == NULL)

     strcat(pgm,”.tny”);

*/

  char *pgm = “test.txt”;

char pgm[120]; /* source code file name */

  if (argc != 2)

    { fprintf(stderr,”usage: %s <filename>\n”,argv[0]);

      exit(1);

    }

  strcpy(pgm,argv[1]) ;

  if (strchr (pgm, ‘.’) == NULL)

     strcat(pgm,”.tny”);

//  char *pgm = “test.txt”;

Table 4-1 测试版和release版的输入修改

char *pgm = "test.txt";只是为便于测试,绑定了一个测试文件,真正运行时将这句代码注释,而运行上面那部分代码,从而只要将文件拖入执行文件中,便可运行生成token序列串。

 

2.     添加了一部分TokenType和关键字。 

typedef enum

    /* book-keepingtokens */

   {ENDFILE,ERROR,

    /* reserved words*/

/*add true false   or  and     not int     bool    string  while   do*/   IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,OR,AND,NOT,INT,BOOL,STRING,WHILE,DO,BOOL_TRUE,BOOL_FALSE,

    /* multicharactertokens */

    ID,NUM,STR,

    /* specialsymbols */

    /*add   >       <=      >=      ,*/

   ASSIGN,EQ,LT,PLUS,MINUS,TIMES,OVER,LPAREN,RPAREN,SEMI,MT,LOE,MOE,COMMA

   } TokenType;

/* lookup table of reserved words */

/*add  true false   or  and      not    int bool        string  while   do*/

static struct{

    char* str;

    TokenType tok;

}reservedWords[MAXRESERVED]

={ {"if",IF},{"then",THEN},{"else",ELSE},{"end",END},

{"repeat",REPEAT},{"until",UNTIL},{"read",READ},

{"write",WRITE},{"true",BOOL_TRUE},{"false",BOOL_FALSE},

{"or",OR},{"and",AND},{"not",NOT},{"int",INT},{"bool",BOOL},

{"string",STRING},{"while",WHILE},{"do",DO}};

3.     扫描器的核心代码中,表驱动的实现。 

typedef enum

{START,INASSIGN,INCOMMENT,INNUM,INID, INGREATER , INSMALLER , INSTRING ,DONE,S_ERROR}

StateType;

/*This is a transformation table used to store all thetransformer in the DFA*/

static struct{

   StateType state;

   int save;

}TTable[11][13];

由状态转换表可知,一开始的表较大,经过改进后,将一部分标识符合并,从而节省了一部分空间。详见状态转换表

表驱动的关键代码为:

/*get the column number of symbols in the transformationtable*/

sym= symNum(c);

/*check if the current char need to save in the currenttoken*/

save= TTable[state][sym].save;

/*state change*/

state= TTable[state][sym].state;

save = TTable[state][sym].save;用来记录该字符是否需要保存到当前token内;

state = TTable[state][sym].state;记录跳转后的状态。

另外,设了个int型变量originState,用来记录原来的状态,用来判断Tokentype。

自定义函数static int symNum(char c) 获得状态转换表中的字符c的列数;

static void TTableInit() 初始化状态转换表。

4.     检查错误代码如下: 

if(c == '\n'&& (originState == INSTRING ||originState == INCOMMENT)){

                  state= S_ERROR;

                  if(originState== INCOMMENT)

                         c= '}';

                  tokenString[tokenStringIndex++]= c;

                  break;

           }

若扫到换行还没有’或者}来终止INSTRING或者INCOMMENT的状态,则认为出错。

五.  运行界面

1.     正常运行界面 

 

                            Figure 5-1 正常运行界面


2.     丢失右半边’}’ 时,显示ERROE 

 

                  Figure 5-2 丢失右半边‘}’时显示ERROR

3.     丢失右半边引号时,显示ERROR 

 

                    Figure 5-3 丢失右半边引号时显示ERROR

4.     检测到错误字符时,显示ERROR


Figure 5-4 4.     检测到错误字符时显示ERROR

六.  备注说明

1.测试代码 

string str;

int x, fact;

str:= 'sample program in TINY+ language-computes factorial' ;

read x;

if x>0 and x<100 then {don't computeif x<=0}

     fact:=1;

     whilex>0 do

            fact:=fact*x;

            x:=x-1

     end;

     writefact

end

2.关于TokenType 

我们是在TINY本来的TokenType的基础上加上STR、MT等类型,没有把所有特殊符号合并成SYM,也没有把所有关键字合并成KEY,每种特殊符号和关键字都有自己特定的TokenType,这样是因为不想修改太多的源程序,还考虑到以后做语法分析等,可以会更加便利。

3.使用语言和编译环境说明 

本程序使用的是C语言,使用编译环境为VS2008 


下载请点击 https://files.cnblogs.com/sandywong/Scaner.rar

posted @ 2010-12-31 21:53  free_swallow  阅读(863)  评论(3编辑  收藏  举报