gcc 源码分析-从一个最简单的程序说起1

本节将以一个最简单的函数来分析gcc 的执行过程,这个函数没有函数体,也没有传入的参数。
例子如下:

void main( )
  {
  
  
  }

执行之后产生的汇编应该是这个样子

.file	"test.c"
gcc_compiled.:
.text	.align 2
.globl _main
_main:
	pushl %ebp
	movl %esp,%ebp
L1:
	leave
	ret

这是用1.40 gcc 的cc1 程序直接产生,后续版本可能会增加其他一些内容,但可以看出这个
版本产生的代码是最简洁的,它只产生了一个栈帧。

首先作词法分析:

我们这里没有按照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];
        }

最后的其他字串将直接返给语法分析器。

词法分析部分就这样简单。

接下来我们将做语法分析...

 

你可能感兴趣的:(GCC,源码分析,gcc,源码,分析)