Redy词法识别--整数与浮点数的合并

本文介绍了Redy语言中整数和浮点数的词法识别过程,通过合并整数与浮点数的状态机来实现。详细探讨了输入类型分析、状态分析表的建立、状态链的构造以及合并后的运行结果,旨在简化识别复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

返回文档首页


(一)简介

代码下载: git clone git://git.code.sf.net/p/redy/code redy-code


这一章内容有:

  1. 整数,长整数,浮点数状态机的合并

(二)整数,浮点数的合并

(1)整数与浮点数的状态机

  在整个Redy词言里面,主要的词文有:变量(包括关键字)、字符串、运算符、浮点数,整数,在这么几个里面,整数与浮点数的合并最难,其它的词文合并在一起识别都非常的简单,所以这里单独的把整数与浮点数合并提取出来,把他们合并成一个大的状态机后,再用这个大的状态机与其它词文的状态机进行合并。

  在合并之前,我们先看一看整数与浮点数的状态机:

整数状态机:

浮点数的状态机:



  要合并两台状态机并不是一件容易的事情,整数的有10个状态,11种输入类型,浮点数有7个状态,5种输入类型,合并起来还是很吃力,不管怎么困难,我们都要合并。下面我们按照的们前面的讲的步骤方法一步一步来。

(2)输入类型分析:

a)对于整数状态机来说,输入11种,前面我们整数识别这一章讲到过,分为:

    1. 数字0   (D0)
    2. 数字1   (D1)
    3. 数字2到7 (D2_7)
    4. 数字8到9  (D8_9)
    5. 字母a和A  (S_a)
    6. 字母B和b (S_b)
    7. 字母c到f和C到F (S_c_f)
    8. 长整数标志符l与L  (S_l)
    9. 八进制前缀o和O (S_o)
    10. 十六进制前缀x和X (S_x)
    11. 除以上字符以外的类型 (other)

其中:

    1. D0_9 包含 D0 , D1  , D2_7 , D8_9
    2. D0_7 包含 D0 , D1  , D2_7
    3. D1_9 包含 D1 , D2_7 , D8_9
    4. S_a_f 包含 S_a , S_b , S_c_f 
b)现在来看浮点数状态机,输入类型有5种,为分:
    1. 点号.     (point)
    2. 数字0到9   (digit)等同于(D0_9)
    3. 字母E和e   (S_e)
    4. 符号+和-    (sign)
    5. 除以上字符的所有字符  (other)
c)对于两个输入类型进行合并得:
    1. 数字0   (D0)
    2. 数字1   (D1)
    3. 数字2到7 (D2_7)
    4. 数字8到9  (D8_9)
    5. 字母a和A  (S_a)
    6. 字母B和b (S_b)
    7. 字母c到d和C到D (S_c_d)
    8. 字母E各e   (S_e)
    9. 字母F和f   (S_f)
    10. 长整数标志符l与L  (S_l)
    11. 八进制前缀o和O (S_o)
    12. 十六进制前缀x和X (S_x)
    13. 点号.     (point)
    14. 符号+和-    (sign)
    15. 除以上字符的所有字符  (other)

其中:

    1. D0_9 包含 D0 , D1  , D2_7 , D8_9
    2. D0_7 包含 D0 , D1  , D2_7
    3. D1_9 包含 D1 , D2_7 , D8_9
    4. S_a_f 包含 S_a , S_b , S_c_d , S_e , S_f 

(3)建立状态分析表

在合并前,先简单复习下前面讲的状态机合并算法:

第一步:

  先把两个自动机的开始状态组合起来,并创建与之等价的一个的新状态,我们把新状态命名为(NumberBegin),然后标记NumberBegin。

第二步:

  找出一个被标记过的状态,对该状态取消标记,然后进行状态转移分析,如果转移的结果是一个未出现过的组合状态,则创建一个与之等价的新状态并标记该新状态。其它的结果则线出一条转移线。

第三步:

  重复第二步,直到没有所有的状态都没有被标记。

第四步:

  把开始状态改为NumberBegin

根据上面的算法,我们先绘制出状态分析表,然后再根据我们的状态分析表,来画状态图

状态分析表为:

状态\输入

Other

D0

D1

D2_7

D8_9

s_a

s_b

s_c_d

s_e

s_f

s_l

s_o

s_x

Point

sign

NumberBegin

(floatBegin,

integerBegin)


IntegerPrefix,intPart

Decimal,intPart









fractionBegin


NumberZero

(integerPrefix,

intPart)


Oct,intPart

intPart


binBegin


exponentBegin


long

octBegin

hexBegin

fractionBegin


Number

(Decimal,

intPart)


Decimal, intPart




exponentBegin


long



fractionBegin


NumberOct

(oct,intPart)


Oct,intPart

intPart




exponentBegin


long



fractionBegin




从上面的分析表可以看出,状态机合并后,会增加四个新的状态。现在我们根据我们分析表来绘制状态图,因为图状态过多,所以我并没有完全给出所有的状态,只是给出新增加的状态可能链接到原状机的状态。


(4)构造状态链

因为状态机在合并后,新增加了四个状态,这四个状态分别为NumberZero, NumberBegin,NumberOct, Number,我们为这四个状态构造状态链,把两个状态机链接在一起,但是在构造之前,我们需要做一件事情是输入类型优化,如果大家仔细观察我们的状态分析表可以发现,在几个输入类型下面,这几个状态并不会发生状态转移,这就说明,这几个输入类型都可以被归纳到类型Other中去。

优化后输入类型有:

  1. 数字0   (D_0)
  2. 数字1_7  (D1_7)
  3. 数字0到9   (D8_9)
  4. 字符b与B   (S_b)
  5. 字符e与E   (S_e)
  6. 字符l与L    (S_l)
  7. 字符o与O   (S_o)
  8. 字符x 与x   (s_x)
  9. 点号     (point)
  10. 除以上以外的字符  (ohter)

其中

  1. D0_7包含D0和D1_7
  2. D1_9包含D1_7和D8_9
  3. D0_9包含D0,D1_7,D8_9
输入类型经过合并以后,从以前的15变成了现在的10个,为我们编写状态链程序节省了不少的时间。

现在我们开始编写状态链程序:
首先,我们先对这四个状态进行申明,以便后面引用:
/*number parts*/
/*number merge float and integer*/
extern struct state nu_begin;
extern struct state nu_zero;
extern struct state nu_oct;
extern struct state nu_number;


第二步,创建一个一维数组,用来映射输入类型。

enum NUMBER_INPUT_TYPES
{
	NU_OTHER=0,
	NU_D0,
	NU_D1_7,
	NU_D8_9,
	NU_S_B,
	NU_S_E,
	NU_S_L,
	NU_S_O,
	NU_S_X,
	NU_POINT,
	NU_INPUT_NUM,
};
char number_input_map[ASCII_NUM]=
{
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,1,2,2,2,2,2,2,2,3,3,0,0,0,0,0,0,
	0,0,4,0,0,5,0,0,0,0,0,0,6,0,0,7,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,
	0,0,4,0,0,5,0,0,0,0,0,0,6,0,0,7,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};


第三步,为每一个状态编写状态链

a)状态NumberBegin在输入类型D0下转移到状态NumberZero,在输入类型point下转移到状态Float::FractionBegin,在输入类型D1_9下转移到状态Number

/*NumberBegin*/
struct state* nu_begin_targets[]=
{
	&lex_state_err,		/*NU_OTHER*/
	&nu_zero,			/*NU_D0*/
	&nu_number,			/*NU_D1_7*/
	&nu_number,			/*NU_D8_9*/
	&lex_state_err,		/*NU_S_B*/
	&lex_state_err,		/*NU_S_E*/
	&lex_state_err,		/*NU_S_L*/
	&lex_state_err,		/*NU_S_O*/
	&lex_state_err,		/*NU_S_X*/
	&ft_frac_begin,		/*NU_POINT*/
};
struct state nu_begin=
{
	"nu_begin",
	TOKEN_UNKOWN,
	NU_INPUT_NUM,
	number_input_map,
	0,
	nu_begin_targets,
	0,
};


b)状态NumberZero在输入类型S_b下转移到状态Integer::IntegerBegin,在输入类型S_o下转移到状态Integer::OctBegin,在输入类型S_x下转移到状态Integer::Hexbegin,在输入类型S_l下转移到状态integer::long,在输入类型D8_9下转移到状态Float::IntPart,在输入类型D0_7下转移到状态NumberOct,在输入类型S_e下转移到状态Float::ExponentBegin,在输入类型point下转移到状态Float::FractionBegin。

/*NumberZero*/
struct state* nu_zero_targets[]=
{
	&lex_state_err,		/*NU_OTHER*/
	&nu_oct,			/*NU_D0*/
	&nu_oct,			/*NU_D1_7*/
	&ft_int_part,		/*NU_D8_9*/
	&ist_bin_begin,		/*NU_S_B*/
	&ft_exp_begin,		/*NU_S_E*/
	&ist_long,			/*NU_S_L*/
	&ist_oct_begin,		/*NU_S_O*/
	&ist_hex_begin,		/*NU_S_X*/
	&ft_frac_begin,		/*NU_POINT*/
};
struct state nu_zero=
{
	"nu_zero(demical)",
	TOKEN_DEC,
	NU_INPUT_NUM,
	number_input_map,
	0,
	nu_zero_targets,
	1,
};


c)状态Number在输入类型point下,转移到状态Float::FractionBegin,在输入类型S_e下转移到状态Float::ExponentBegin,在输入类型S_l下转移到状态integer::long,在输入类型D0_9下转移到自身。

/*NUMBER*/
struct  state* nu_number_targtes[]=
{
	&lex_state_err,		/*NU_OTHER*/  
	&nu_number,			/*NU_D0*/
	&nu_number,			/*NU_D1_7*/
	&nu_number,			/*NU_D8_9*/
	&lex_state_err,		/*NU_S_B*/
	&ft_exp_begin,		/*NU_S_E*/
	&ist_long,			/*NU_S_L*/
	&lex_state_err,		/*NU_S_O*/
	&lex_state_err,		/*NU_S_X*/
	&ft_frac_begin,		/*NU_POINT*/
};
struct state nu_number=
{
	"nu_number(demical)",
	TOKEN_DEC,
	NU_INPUT_NUM,
	number_input_map,
	0,
	nu_number_targtes,
	1,
};


e)状态NumberOct在输入类型D0_7下转移到自身,在输入类型S_e下转移到状态Float::ExponentBegin,在输入类型S_l下转移到状态integer::long,在输入类型D8_9下转移到状态Float::intPart.

/*NumberOct	*/
struct state* nu_oct_targtes[]=
{
	&lex_state_err,		/*NU_OTHER*/ 
	&nu_oct,			/*NU_D0*/
	&nu_oct,			/*NU_D1_7*/  
	&ft_int_part,		/*NU_D8_9*/
	&lex_state_err,		/*NU_S_B*/
	&ft_exp_begin,		/*NU_S_E*/
	&ist_long,			/*NU_S_L*/
	&lex_state_err,		/*NU_S_O*/
	&lex_state_err,		/*NU_S_X*/
	&ft_frac_begin,		/*NU_POINT*/
};
struct state nu_oct=
{
	"nu_oct(oct)",
	TOKEN_OCT,
	NU_INPUT_NUM,
	number_input_map,
	0,
	nu_oct_targtes,
	1,
};


到现在为些,我们已经完成了浮点数与整数状态机的合并,大家可以在下载下来的文件夹下面的tutorial/lexical/sl_number中找到所有合并后的代码,sl_integer是整数状态机的状态链,sl_float是浮点数状态机的状态链,sl_number为合并后新增四个状态的状态链程序。

(5)运行结果



返回文档首页




























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值