分享
 
 
 

make_func.y源码分析

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

阅读本文需要了解:词法分析,语法分析的基本知识,这方面的知识最好是去找本教材来好好学习一遍;还需要掌握flex(或lex),bison(或yacc)的基本用法,这方面的知识网上很多,比如:yacc与lex快速入门,各自的手册——flex manualbison manual。所有这些知识的掌握至少需达到这样的程度:阅读本文出现疑惑时知道在哪找答案。

一份mudos源码是必不可少的。为了方便的编译和处理这些源码,最好是处于unix环境,windows用户可以安装cygwin,在完全安装之后,将获得gcc、flex、bison等常用工具。编译MudOS源码比较繁琐,这里有个MudOS编译手册可做参考。

源码分析

本文所分析的源代码见:make_func.y

定义部分

该部分包括直接进入输出文件的c代码(2行到53行),以及用来建立分析程序的有关记号、数据结构以及文法规则的信息(56行到66行)。

16 – 23 这里声明的全局变量将在解析的同时被赋值,这些值,在执行edit_source -build_efuns时用来生成LPC语法的仿函数列表,同时也自动生成编译MudOS所需要的一些头文件。

37 – 51 LPC支持的各种数据类型。

56 – 59 默认情况下,actions和词法分析的返回值为整数,为了让解析程序支持多种数据类型,定义一个union,在bison程序处理后的文件make_func.tab.c中,这个union定义成:

typedef union {

int number;

char *string;

} yystype;

62 定义EBNF终结符号。

64 定义非终结符号。其返回值相关数据类型为int。ID在终结符号声明中出现,仍为终结符。

66 非终结符号。其返回值相关数据类型为char *。NUM在终结符号声明中出现,仍为终结符。

如果61行到65行按照下面这种方式声明,用bison处理后的文件make_func.tab.c将一模一样:

%token <string> ID

%token <number> NUM

%token DEFAULT OPERATOR

%type <number> type arg_list basic typel arg_type typel2

%type <string> optional_ID optional_default

词法分析

该部分定义解析程序如何从源文本中分析出单词的规则。这项工作可以交给flex或者lex来完成,但是由于这个解析程序比较简单,因此自定义词法分析代码(328行到414行)。

330 词法分析函数必须声明为 int yylex()

334 yyin声明于edit_source.c,为func_spec.cpp的文件流。

338 – 340 记录源文件的行号。

341 – 347 当源文件某行以”!”开头时,表示解析文件失败。这种情况可能出现在链接了两个或三个内存分配函数库的情况下,见macros.h93行到95行:

#if (defined(SYSMALLOC) + defined(SMALLOC) + defined(BSDMALLOC)) > 1

!Only one malloc package should be defined

#endif

执行edit_source –build_func_spec “gcc –E”指令获得func_spec.c的源代码列表时,可能将” !Only one malloc package should be defined”这行包含到func_spec.cpp中。

348 – 363 当源文件某行以” #” 开头时,文件名和行号将保存到current_file和current_line中,这类似于预编译指令#line,默认情况下,发现错误的时候,报告的是func_spec.cpp的文件名称及行号,如果解析文本解析到以”#”开头的行时,比如” #1 "op_spec.c" 1”,紧接着解析出现错误,将报告的是”op_spec.c”第一行,这将保证报告出错位置的正确性。

364 – 366 遇到文件结束标志,解析完毕,返回-1。

368 – 364 解析到数字,返回NUM终结符号。

385 – 387 解析到字符串,返回ID、DEFAULT、OPERATOR的其中之一。

397 – 403标示符过长的错误处理。

406 – 407 如果匹配字符串”default”,则返回DEFAULT的值,这个值在bison处理后的文件make_fucn.tab.c中出现:”#define DEFAULT 259”

408 – 409如果匹配字符串”operator”,则返回OPERATOR的值,这个值在bison处理后的文件make_fucn.tab.c中出现:”#define OPERATOR 260”

411 – 413 其他字符串都将被视为ID,它们本身的值,比如”to_int”被压入到yylval.string中,这个值在action代码里的表现形式为$n,见81行和194行。在定义部分,ID相关的数据类型为char *。

规则部分

该部分包括EBNF文法规则,以及在识别出相关的文法规则时被执行的action代码部分(69行到231行)。

待解析的句型实例:

operator add, subtract, multiply, divide, mod, and, or, xor, lsh, rsh;

int call_out(string | function, int,...);

除去相关的action代码,余下的EBNF文法规则整理如下:

specs à /* empty */

| specs spec ;

spec à operator

| func;

operator à OPERATOR op_list ';' ;

op_list à op

| op_list ',' op ;

op à ID ;

func à type ID optional_ID '(' arg_list optional_default ')' ';' ;

optional_ID à ID

| /* empty */ ;

optional_default à /* empty */

| DEFAULT ':' NUM

| DEFAULT ':' ID ;

type à basic

| basic '*' ;

basic à ID ;

arg_list à /* empty */

| typel2

| arg_list ',' typel2 ;

typel2 à typel ;

arg_type à type ;

typel à arg_type

| typel '|' arg_type

| '.' '.' '.' ;

73 – 91 寻找句型:”OPERATOR ID( ,ID)* \;” ID的值将保存到oper_codes中,同时记录operator的个数op_code。

93 – 231 寻找句型:”(ID|ID \*) ID [ID]{0,1} \(…”(不知道它的正则表达式该怎么写L,路漫漫其修远兮)

93 为empty时,optional_ID的值为””,否则直接返回ID的值。

95 为empty时,optional_default的值为”DEFAULT_NONE”。

96 – 101 匹配句型”DEFAULT : NUM”,将NUM的值转换成string,令optional_default的值为这个string。

102 – 107 匹配句型”DEFAULT : ID”,如果ID的值不为”F_THIS_OBJECT”,解析失败,否则,令optinal_default的值为”DEFAULT_THIS_OBJECT”

187 – 231 描述了arg_list的规则,这些代码比较复杂,整理为下面这张表,表中的第一列表示arg_list的各种句型,第一行为程序中出现全局变量和arg_list本身的值,其他行列的值表示这些全局变量在arg_list匹配不同句型的情况下的值,之所以将它们总结出来,是因为在func的action函数里要用到:

arg_list

min_arg

limit_max

curr_arg_type_size

/*empty*/

0

-1

0

0

ID

(ID != VOID)

1

-1

0

1

ID

(ID == VOID)

1

0

0

0

ID | ID

1

-1

0

2

ID | ID

(某个ID == VOID)

1

0

0

1

ID, ID

2

-1

0

3

ID, ID

(某个ID == VOID)

1

0

0

2

1

-1

1

0

ID, …

2

1

1

1

……(省略)

现在来分析一下各个全局变量的意义。

arg_list:函数参数的个数。

min_arg:函数中参数的最小数量,这个数量由参数中出现”VOID”或”…”来决定。

limit_max:表示是否限制参数个数,为1的时候不限制,为0的时候有最大参数限制,这个限制为arg_list的个数。

curr_arg_type_size:这个参数和arg_list有关,如果是逗号相隔的参数列表,那么两个参数之间必须有个0作为分隔符,因此如果是ID, ID,curr_arg_type_size的值为3;如果某个ID为VOID,将不计算在内。

114 – 116 如果在arg_list的词法分析中,min_arg的值一直保持为-1,那么将arg_list的值赋给它,min_arg的最大值为4,超过则报错,程序退出。

117 – 139 如果optional_id为NULL,则对f_name和efun1_code或者efun_code赋值,区别在于其参数的个数,如果是单参数则赋值到efun1_code,其他将赋值到efun_code。

139 – 149 如果optional_id不为NULL,例如:object this_user this_player( int default: 0); 这表示这个函数是一个alias,f_name = “F_THIS_PLAYER | F_ALIAS_FLAG”

150 – 167 将参数列表curr_arg_types赋值到arg_types中,但是如果之前已经有curr_arg_types 中的连续元素存在,将不进行赋值操作。这一点,保证,参数列表的唯一性,见curr_arg_types和arg_types的声明注释:Store the types of the current efun. They will be copied into the arg_types list if they were not already there (to save memory).

167 – 170 符合条件的源文件只有:unknown call_other(object | string | object *, string | mixed *,...);如果遇到这样的句型,将type的值,也就是$1改为MIXED。

171 – 174 对buff赋值,其赋值语句可解释为:ID,f_name,0,0,min_arg,limit_max ? -1 : arg_list,type != VOID ? ctype(type) : "TYPE_NOVALUE", etype(0), etype(1), eytpe(2), etype(3), i, optional_default

178 – 180 追加buff到buf数组中。

235 – 261 取得efuns的返回值数据类型。

264 – 326 取得参数的数据类型。由于efuns的参数最大值为4,因此,在171 – 174行对buff赋值的时候只需要执行4次etype函数,如果参数个数不足4个,则etype返回值为T_ANY。

参考资料:

[1] Kenneth C. Louden. 冯博琴,冯岚(译). 《编译原理及实践》. 机械工业出版社

[2] Stephen C. Johnson. Yacc: Yet Another Compiler-Compiler

[3] Yacc与lex快速入门:

http://www-900.ibm.com/developerWorks/cn/linux/sdk/lex/index.shtml

[4] Bison manual:

http://tinf2.vub.ac.be/~dvermeir/courses/compilers/bison-1.25/bison_toc.html

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有