本节将以一个最简单的函数来分析gcc 的执行过程,这个函数没有函数体,也没有传入的参数。
例子如下:
void main( ){}
首先作词法分析:
我们这里没有按照gcc源代码的做法,用手工做词法分析,而是采用采用词法分析工具flex,来完成词法分析,这样做的结果,代码看起来很简洁直观。涉及到的词法分析规则如下:
void { yylval.ttype = ridpointers[RID_VOID]; return TYPESPEC; }
[ \t] ;
[a-zA-Z0-9]+ { yylval.ttype = get_identifier (yytext);lastiddecl = lookup_name (yylval.ttype);if (lastiddecl != 0 && TREE_CODE (lastiddecl) == TYPE_DECL){return TYPENAME;}return IDENTIFIER;}\n { lineno++; }
. {return yytext[0];}
设想一下,当词法分析器遇到void这个字串时,就将该字串归结为一个单词,随后执行下列语句:
yylval.ttype = ridpointers[RID_VOID]
ridpointers是一个tree 类型的数组,当程序启动时,会对该数组作初始化动作:
ridpointers[(int) RID_VOID] = get_identifier ("void");
get_identifier实质是返回一个tree_identifier类型的tree_node节点。这个节点的
相关属性为
length: id 长度,
pointer: 保存为id值,字符串类型比如int 就为"int",void 就为"void".
get_identifier首先去hash表中查找名字为"void" 的tree_identifier类型的tree_node节点,没找到就创建一个,然后把这个tree_node节点返回;
这样当前词法分析的当前值就为名字为"void" 的tree_identifier类型的节点,最后返回TYPESPEC,表明是一个保留字。
接下来的:
[ \t] ;
表明遇到空格和字表符不做任何处理;
[a-zA-Z0-9]+ {....}
表明现在识别到以字母开头的字串,在本样例中表明词法分析器识别到了main字串,后续处理调用get_identifier函数,查找当前hash表是否有该tree_identifier类型的tree_node节点,没有则创建,并返回该节点,
调用lookup_name,看看该tree_identifier是否在全局或局部变量域已经有定义,如果没有则认为该节点是identifier节点,如果有则需要进一步确认是否表示数据类型的节点。
\n { lineno++; }
遇到换行符号,行数加1;
. {
return yytext[0];
}
最后的其他字串将直接返给语法分析器。
词法分析部分就这样简单。
接下来我们将做语法分析...