ucc编译器(词法分析)

Posted 费晓行

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ucc编译器(词法分析)相关的知识,希望对你有一定的参考价值。

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

 

    学过编译器的同学都知道,词法分析是编译器里面最基础的一条。之前,在学校读书的时候,老师也会告诉我们这个时候,应该用状态机来实现。此外,必须要先要做一遍词法分析,然后才能做语法分析,其实不然。至少,我们今天的ucc里面,其实语法分析和词法分析是一起做的。

 

    另外一点,和学校里面不一样的是,很多场合,大家也喜欢用flex工具自动生成词法分析的代码。毕竟,只要会写正则表达式,就可以完成很多的工作。这个比手写容易很多。

 

1、词法分析的文件

lex.c

https://github.com/nobled/ucc/blob/master/ucl/lex.c

 

2、给语法解析提供的接口

int GetNextToken(void)
{
	int tok;

	PrevCoord = TokenCoord;
	SkipWhiteSpace();
	TokenCoord.line = LINE;
	TokenCoord.col  = (int)(CURSOR - LINEHEAD + 1);

	tok = (*Scanners[*CURSOR])();
	return tok;
}

 

3、注册词法分析回调函数

void SetupLexer(void)

 

4、解析回调注册

{
    // other code

    Scanners[END_OF_FILE] = ScanEOF;
	Scanners['\\''] = ScanCharLiteral;
	Scanners['"']  = ScanStringLiteral;
	Scanners['+']  = ScanPlus;
	Scanners['-']  = ScanMinus;
	Scanners['*']  = ScanStar;
	Scanners['/']  = ScanSlash;
	Scanners['%']  = ScanPercent;
	Scanners['<']  = ScanLess;
	Scanners['>']  = ScanGreat;
	Scanners['!']  = ScanExclamation;
	Scanners['=']  = ScanEqual;
	Scanners['|']  = ScanBar;
	Scanners['&']  = ScanAmpersand;
	Scanners['^']  = ScanCaret;
	Scanners['.']  = ScanDot;
	Scanners['{']  = ScanLBRACE;
	Scanners['}']  = ScanRBRACE;
	Scanners['[']  = ScanLBRACKET;
	Scanners[']']  = ScanRBRACKET;
	Scanners['(']  = ScanLPAREN;
	Scanners[')']  = ScanRPAREN;
	Scanners[',']  = ScanCOMMA;
	Scanners[';']  = ScanSEMICOLON;
	Scanners['~']  = ScanCOMP;
	Scanners['?']  = ScanQUESTION;
	Scanners[':']  = ScanCOLON;

}

 

5、举例说明

5.1 一般的符号解析,比如加号解析

static int ScanPlus(void)
{
	CURSOR++;
	if (*CURSOR == '+')
	{
		CURSOR++;
		return TK_INC;
	}
	else if (*CURSOR == '=')
	{
		CURSOR++;
		return TK_ADD_ASSIGN;
	}
	else
	{
		return TK_ADD;
	}
}

    注意这里的加号解析,它有可能是+,有可能是++,也有可能是+=,其实有三种情况需要处理。不失一般性,我们可以找到减号的解析函数,

static int ScanMinus(void)
{
	CURSOR++;
	if (*CURSOR == '-')
	{
		CURSOR++;
		return TK_DEC;
	}
	else if (*CURSOR == '=')
	{
		CURSOR++;
		return TK_SUB_ASSIGN;
	}
	else if (*CURSOR == '>')
	{
		CURSOR++;
		return TK_POINTER;
	}
	else
	{
		return TK_SUB;
	}
}

    加号要比加号复杂一点,除了-,它还有可能是--,-=,->,所以总共有四种情况。

 

5.2 有些符号,因为实在不可能出现其他情况,根本不需要往后看,比如[、]、{、}等等,因此对它们的处理其实直接可以用macro宏来表示,

#define SINGLE_CHAR_SCANNER(t) \\
static int Scan##t(void)       \\
{                              \\
    CURSOR++;                  \\
    return TK_##t;             \\
}

 

5.3 对变量的解析

static int ScanIdentifier(void)
{
	unsigned char *start = CURSOR;
	int tok;

	if (*CURSOR == 'L')
	{
		if (CURSOR[1] == '\\'')
		{
			return ScanCharLiteral();
		}
		if (CURSOR[1] == '"')
		{
			return ScanStringLiteral();
		}
	}

	CURSOR++;
	while (IsLetterOrDigit(*CURSOR))
	{
		CURSOR++;
	}

	tok = FindKeyword((char *)start, (int)(CURSOR - start));
	if (tok == TK_ID)
	{
		TokenValue.p = InternName((char *)start, (int)(CURSOR - start));
	}

	return tok;
}

    注意,对变量的解析这部分,还会进一步分成单字符、字符串、关键字、普通变量四种情况的解析。因此,它的结果可能有四种形式。

 

5.4 对数字的解析

static int ScanNumericLiteral(void)
{
	unsigned char *start = CURSOR;
	int base = 10;

	if (*CURSOR == '.')
	{
		return ScanFloatLiteral(start);
	}

	if (*CURSOR == '0' && (CURSOR[1] == 'x' || CURSOR[1] == 'X'))
	{
		CURSOR += 2;
		start = CURSOR;
		base = 16;
		if (! IsHexDigit(*CURSOR))
		{
			Error(&TokenCoord, "Expect hex digit");
			TokenValue.i[0] = 0;
			return TK_INTCONST;
		}
		while (IsHexDigit(*CURSOR))
		{
			CURSOR++;
		}
	}
	else if (*CURSOR == '0')
	{
		CURSOR++;
		base = 8;
		while (IsOctDigit(*CURSOR))
		{
			CURSOR++;
		}
	}
	else
	{
		CURSOR++;
		while (IsDigit(*CURSOR))
		{
			CURSOR++;
		}
	}

	if (base == 16 || (*CURSOR != '.' && *CURSOR != 'e' && *CURSOR != 'E'))
	{
		return ScanIntLiteral(start, (int)(CURSOR - start), base);
	}
	else
	{
		return ScanFloatLiteral(start);
	}
}

    对数字的解析比较复杂,这个里面有可能是整数,也有可能是浮点数。整数里面还有10进制、16进制,浮点数里面有单精度和双精度。当然,不管结果是什么,都不外乎这两种情形。

 

5.5 其他支撑函数

    这部分函数也有一些,比如检查是否是数字或字母,是否是关键字,是否跳过空格等等。这部分函数也非常关键,但是他们不是主要的接口函数。

 

    记得读书的时候,这部分考虑的主要就是状态机的部分,也就是fsm。只要有一些fsm的基础知识,用起来还是比较容易地。

 

以上是关于ucc编译器(词法分析)的主要内容,如果未能解决你的问题,请参考以下文章

ucc编译器(语义分析)

编译原理 实验一 java语言实现对C语言词法分析

编译原理 实验一 java语言实现对C语言词法分析

实验一 词法分析器+编译原理

Second-词法分析

ucc编译器(中间代码生成)