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编译器(词法分析)的主要内容,如果未能解决你的问题,请参考以下文章