# 词法分析器在程序编译过程中所处的位置

# 词法分析器

Lexical Analyzer ,输入源程序,扫描器 Scanner 从左至右逐个字符地对源程序进行扫描,产生多个单词符号;单词符号的种类有

  • 基本字(关键字): beginrepeatfor 等程序语言定义好的
  • 标识符:用来表示各种名字,如变量名、数组名和过程名
  • 常数:各种类型的常数
  • 运算符: +、-、*、/
  • 界符: ,、;、()、space符

输出的单词符号的表示形式为 (单词种别,单词自身的值) ,单词种别通常用整数编码表示

  • 若一个种别只有一个单词符号,则种别编码就代表该单词符号,假定基本字、运算符、界符都是一符一种。
  • 若一个种别有多个单词符号,则对于每个单词符号,给出种别编码和自身的值
  • 标识符单列一种,标识符自身的值表示成按机器字节划分的内部码。
  • 常数按类型分种,常数的值则表示成标准的二进制形式

# 如何设计

# 扫描缓冲区

两个指针分别指向起点和搜索位置,考虑到单词长度超过缓冲区的长度,造成存储不连续,可以分为两个半区互补使用。

如果某单词的结尾在一个半区找不到,那么在下一个半区一定能找得到,所以半区的长度就是程序语言允许的单词最大长度,比如某编程语言的标识符长度不超过 128 ,就可以推断出编译器的扫描缓冲区总长度为 256

# 状态转换图

状态转换图是一张有限方向图,节点代表状态,用圆圈表示,状态之间用箭弧连接,上面的标记(字符)代表射出的结点状态下可能出现的输入字符或字符类,一张转换图只包含有限个状态,其中有一个为初态,至少有一个终态。
状态转换图可用于识别一定的字符串,若存在一条从初态到某一终态的道路,且这条路上所有弧上的标记符连接成的字等于 α ,则称 α 被该状态转换图所识别。

终态上的 * 代表最后一个输入的字符不属于刚才读入的单词,将其退回去。

几点限制,不必使用超前搜索

  • 所有基本字都是保留字,用户不能用它们作自己的标识符
  • 基本字作为特殊的标识符来处理,使用保留字表
  • 如果基本字、标识符和常数(或括号)之间没有确定的运算符或界符作为间隔,则必须使用一个空白符作间隔
#include<bits/stdc++.h>
using namespace std;
const int max_word = 505;
char token[12];
char in[105];
FILE *fin,*fout;
int cnt = 0,token_num = 0;
int row = 1;
int flag = 0;
char ch;
char datain[255];
// 关键字
const char keyWord[13][20] = {"main","if","else","do","while","for","switch",
                              "case","int","double","float","long","void"
                             };
void init_token();
void getbc();
void m_getch();
void concat();
int digit();
int letter();
int reserve();
int scanner();
int main()
{
	int temp;
	char input[30];
	cout<<"请输入源文件名:";
	for(;;) {
		cin>>input;
		if((fin = freopen(input,"r",stdin))!=NULL){
			cout << "从 "<<input<<" 读取"<<endl;
			while((scanf("%[^`]s",&datain))!=EOF)
				printf(datain);
			break;
		}
		else
			cout<<"路径输入有误"<<endl;
	}
	freopen(input,"r",stdin);
	while(1) {
		temp = scanner();
		if(temp==-1) {
			break;
		}
		switch(temp) {
			case -10:
				cout<<"第 "<<row<<" 行 识别有误."<<endl;
				break;
			default:
				cout<<"第 "<<row<<" 行 <"<<temp<<","<<token<<">"<<endl;
				break;
		}
	}
	return 0;
}
void init_token()
{
	int i;
	for(i = 0; i < 12; i++) {
		token[i] = 0;
	}
}
void getbc()
{
	while(ch == ' ' || ch == '\t' || ch == '\n') {
		if(ch == '\n') {
			row++;// 顺便记录行数
		}
		ch=getc(fin);
	}
}
void m_getch()
{
	if(flag == 0) {
		ch = getc(fin);
	}
}
void concat()
{
	token[token_num++] = ch;
	ch = getc(fin);
}
int digit()
{
	if (ch >= '0'&&ch <= '9')
		return 1;
	else
		return 0;
}
int letter()
{
	if (ch >= 'a'&&ch <= 'z' || ch >= 'A'&&ch <= 'Z')
		return 1;
	else
		return 0;
}
int reserve()
{
	for(int i = 0; i <13; i++) {
		if(strcmp(token,keyWord[i]) == 0) {
			//3 为关键词
			return 3;
		}
	}
	//2 为标识符
	return 2;
}
int scanner()
{
	init_token();
	m_getch();
	flag = 1;
	getbc();
	token_num = 0;
	if(letter()) {
		while(letter()||digit()) {
			concat();
		}
		token[token_num++] = '\0';
		reserve();
	}
	// 是数字
	else if(digit()) {
		while(digit() || ch == '.') {
			concat();
		}
		return 1;
	} else {
		token[token_num++] = ch;
		switch(ch) {
			case '(':
				ch = getc(fin);
				return 16;
			case ')':
				ch = getc(fin);
				return 17;
			case '{':
				ch = getc(fin);
				return 33;
			case '}':
				ch = getc(fin);
				return 34;
			case '+':
				ch = getc(fin);
				if(ch == '+') {
					token[token_num++] = ch;
					ch = getc(fin);
					return 29;
				} else {
					return 18;
				}
			case '-':
				ch = getc(fin);
				if(ch == '-') {
					concat();
					return 30;
				} else {
					return 19;
				}
			case '*':
				ch = getc(fin);
				if(ch == '/') {
					concat();
					return 32;
				} else {
					return 20;
				}
			case '/':
				ch = getc(fin);
				if(ch == '*') {
					concat();
					return 31;
				} else {
					return 21;
				}
				// 这里要重新编码
			case '=':
				ch = getc(fin);
				if(ch == '=') {
					concat();
					return 23;
				} else {
					return 22;
				}
			case '>':
				ch = getc(fin);
				if(ch == '=') {
					concat();
					return 24;
				} else {
					return 23;
				}
			case '<':
				ch = getc(fin);
				if(ch == '=') {
					concat();
					return 26;
				} else {
					return 25;
				}
			case ';':
				ch = getc(fin);
				return 27;
			case '"':
				ch = getc(fin);
				return 28;
			case '!':
				ch = getc(fin);
				if(ch == '=') {
					concat();
					return 37;
				} else {
					return 36;
				}
			case '#':
				ch = getc(fin);
				return -2;
			case ',':
				ch = getc(fin);
				return 35;
			case EOF:
				return -1;
			default:
				ch = getc(fin);
				return -10;
		}
	}
}

示例 data.txt

int main()
{
        int b=10;float f;
        f+=b;
        return 0;
}

更新於 閱讀次數

請我喝[茶]~( ̄▽ ̄)~*

fygod 微信支付

微信支付

fygod 支付寶

支付寶

fygod PayPal

PayPal