【コンパイル原理】C ++は字句解析を実現します(アノテーション付きで実行可能)

目的:

単語読み取りプロセスをコンパイルします。入力ソースプログラムから、独立した意味を持つ単語、つまり、基本的な予約語、識別子、定数、演算子、および区切り文字の5つのカテゴリを識別します。そして、各単語の内部コードと単語記号の値を順番に出力します。

字句解析、文法解析、意味解析の違い:

1.字句解析

  字句解析は、コンパイルプロセスの最初の段階です。この段階のタスクは、次のように見ることができます。ソースプログラムを左から右に文字ごとに読み取り、そこから各「単語」記号、つまり、ソースプログラム文字ストリームをスキャンし、単語形成規則に従って単語(単語記号または記号とも呼ばれます)を認識します。

  字句解析プログラムを通じて、ソースプログラムを読み取り、記号を認識するタスクが実現されます。字句解析プロセスは、言語の字句規則に基づいています。

  出力:字句解析プログラムによって出力される「単語」は、多くの場合、2つのタプル、つまり単語のタイプと単語自体の値の形式で出力されます。

  認識:言語を構成する単語を定義する形態は、言語の最小単位です。

2.構文解析:

  文法分析は、コンパイルプロセスの論理的な段階です。この段階のタスクは、「プログラム」、「文」、「表現」などの字句解析に基づいて、単語シーケンスをさまざまな文法句に結合することです。

  文法は、ユーザーデータと制御情報の構造と形式です。

  認識:文法-英翻訳の文法のように、リストを意味のあるフレーズや文に編成するためのルール。

3.構文解析

  セマンティック分析は、コンパイルプロセスの論理的な段階です。セマンティクスは、制御情報の各部分の意味を説明することであり、送信する必要のある制御情報の種類、完了したアクション、および応答の種類を指定します。この段階でのタスクは、構造に応答することです。正しいソースプログラムのコンテキスト依存レビューを実行し、レビューを入力します。

  後でコード生成フェーズで使用するために型情報を収集します。

  セマンティック分析はタイプを確認し、エラーを報告します。配列変数を式で使用できず、代入ステートメントの右端と左端のタイプが一致しません。

  認識:意味論-文脈と組み合わせて、文の真の意味、つまり、中国語を入力した後に翻訳された英語の意味、または英語を入力した後に翻訳された中国語を推測できます。

実験コード:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <string>
#include <cstring>
using namespace std;


int seekresult;//fseek的时候用来接着的
string word=" ";//字符串,当前词
char ch; //每次读进来的一个字符
int num = 0;//每次读进来的一个字符
int rows = 1;//行数
int cols=1;//列数
bool flag;//文件是否扫描结束
int type;//单词类型

string Keyword[8]={ "main","float","int","scanf","cos","sqrt","if","printf" };
char Jiefu[36][4] = { ';','(',')','^',',','#','%','[',']','{','}','.' };
char Mark[8] = { '-','*','/','>','<','=','+','!' };
char DigitBTable[1000][40] = {};//常数表
int Inum = 0;
int Dnum = 0;
char IDentifierTable[1000][40] = {};//标识符表


//判断是否为关键词
bool IsKeyword(string word) {
	for (int i = 1; i <= 8; i++) {
		if (Keyword[i] == word)
			return true;
	}
	return false;
}

//判断是否为标点符号
bool IsMark(char mark) {
	for (int i = 1; i <= 8; i++) {
		if (Mark[i] == mark)
			return true;
	}
	return false;
}

//判断是否为关系运算符
bool IsGuanxiyunsuanfu(char ch) {
	if (ch == '=' || ch == '<' || ch == '>')
		return true;
	else
		return false;
}

//判断是否为字母
bool IsLetter(char ch) {
	if ((ch >= 'A'&&ch <= 'Z')||(ch>='a'&&ch<='z'))
		return true;
	else
		return false;
}

//判断是否为运算符
bool IsSuanshuyunsuanfu(char ch) {
	if (ch == '+' || ch == '-' || ch == '*')
		return true;
	else
		return false;
}

//判断是否为界符
bool IsJiefu(char ch) {
	int i = 0;
	int temp = 0;
	for (i = 0; i < 14; i++)
	{
		if (ch == Jiefu[i][0]) {
			temp = 1;
			break;
		}
	}
	if (temp == 1)
		return true;
	else
		return false;
}

//判断是否为数字
bool IsDigit(char ch) {
	if (ch >='0' &&ch <= '9')
		return true;
	else
		return false;
}


//从文件中读取一个词
int Scanner(FILE *fp) { // FILE *fp 定义了一个文件指针通过操作该指针可以进行文件读写
	//先读写一个字符,赋值给ch
	ch = fgetc(fp);
	
	if (feof(fp)) {   //feof(fp)函数用于测试fp文件指针是否已经到达文件结尾,已达到则返回1,反之返回0.
		flag = 0;
		       return 0;
	}

	else if (ch == ' ') {
		cols++;
		return 0;
	}

	else if (ch == '\n') {
		rows++;
		cols = 1;
		return 0;
	}

	//如果是字母开头或者_开头,判断是关键字还是标识符
	else if (IsLetter(ch) || ch == '_') {
		word += ch;
		cols++;
		while ((ch = fgetc(fp)) && (ch == IsLetter(ch) || IsDigit(ch) || ch == '_')) {
			word += ch;
			cols++;
		}
		//文件读完,返回true
		if (feof(fp)) {
			flag = 0;
			return 1;
		}
		//检验是否是关键字
		for (int i = 1; i <= 8; i++) {
			if (word == Keyword[i]) {
				//seek_cur当前位置,fseek函数作用:文件位置指针从当前位置移一个位置
				seekresult = fseek(fp, -1, SEEK_CUR);
					//5+i-1:关键字
					return  5 + i - 1;
			}
		}
		for (int Ii = 0; Ii < Inum; Ii++) {
			if (Inum != 0 && strcmp(IDentifierTable[Ii], word.c_str())== 0){
				seekresult = fseek(fp, -1, SEEK_CUR);
					//1:标识符
					//return 1
					return 1000 + Ii + 1;
			}

		}
		strcpy(IDentifierTable[Inum], word.c_str());
			Inum = Inum + 1;
			//写追加
			ofstream Arithmetic_operator;
			Arithmetic_operator.open("IDentifierTable.txt",ios::app);
			Arithmetic_operator << word << " " << endl;
			Arithmetic_operator.close();

			seekresult = fseek(fp, -1, SEEK_CUR);
			//1:标识符
			//return 1
			return 1000 + Inum;

	}
	else if (IsSuanshuyunsuanfu) {
		word += ch;
		cols++;
		 //4是运算符
		return 4;

	}
	else if (IsDigit(ch)) {
		word += ch;
		cols++;
		while ((ch = fgetc(fp)) && IsDigit(ch)) {
			word += ch;
			cols++;
		}
		int Di = 0;
		for (Di = 0; Di < Inum; Di++) {
			if (Dnum != 0 && strcmp(DigitBTable[Di], word.c_str()) == 0) {
				seekresult = fseek(fp, -1, SEEK_CUR);
				//常数为2
				//return 2
				return 2000 + Di + 1;
			}
		}
		strcpy(IDentifierTable[Inum], word.c_str());
		Dnum = Dnum + 1;
		//写追加
		ofstream Arithmetic_operator;
		Arithmetic_operator.open("DigitBTable.txt", ios::app);
		Arithmetic_operator << word << " " << endl;
		Arithmetic_operator.close();

		/*if(feof(fp)){
		flag = 0;
		return 2;
	} */

		seekresult = fseek(fp, -1, SEEK_CUR);
			//2:数字(常量)
			return 2000 + Dnum;
	}

	//检验界符5
	else if (IsJiefu(ch)) {
	int Ji;
	for (Ji = 0; Ji < 12; Ji++) {
		if (ch == Jiefu[Ji][0]) {
			break;
		}
	}
	word += ch;
	cols++;
	return (6 - 1 + 32 + Ji);//界符6-1+32+i
}

//检验关系运算符4 :<=、>=、<>、==、 < 、>
	else if (IsGuanxiyunsuanfu(ch))
	{
	cols++;
	word += ch;
	//检验  <> <=
	if (ch == '<')
	{
		ch = fgetc(fp);
		if (ch == '>' || ch == '=')
		{
			word += ch;
			cols++;
			return 4;
		}
	}
	//检验  >= ==
	else {
		ch = fgetc(fp);
		if (ch == '=')
		{
			word += ch;
			cols++;
			return 4;
		}
	}
	if (feof(fp)) {
		flag = 0;
	}
	seekresult = fseek(fp, -1, SEEK_CUR);
	//3:算数运算符 
	return 3;
	}

	//首字符是 / 有可能是除号 也有可能是注释
	else if (ch == '/')
	{
	cols++; word += ch;
	ch = fgetc(fp);
	//这种情况是除号
	if (ch != '*' && ch != '/')
	{
		seekresult = fseek(fp, -1, SEEK_CUR);
		//3:算数运算符 
		return 3;
	}
	//注释符//:这一行剩下的全被注释了
	if (ch == '/')
	{
		word.clear();
		while ((ch = fgetc(fp)) && ch != '\n' && !feof(fp))
		{
		}
		if (feof(fp)) {
			flag = 0;
			return 0;
		}
		else {
			seekresult = fseek(fp, -1, SEEK_CUR);
		}
		rows++; cols = 1;
		return 0;
	}
	if (ch == '*')
	{
		bool flag5 = 1;
		while (flag5)
		{
			word.clear();
			ch = fgetc(fp);
			cols++;
			if (ch == '\n')
			{
				rows++;
				cols = 1;
			}
			if (ch != '*')
				continue;
			else
			{
				ch = fgetc(fp);
				cols++; if (ch == '\n') { rows++; cols = 1; }
				if (ch == '/') {
					flag5 = 0;
				}
				else continue;
			}
			if (feof(fp))
			{
				flag = 0;
				return 0;
			}
		}
	}
	}
	else {
	word += ch;
	cols++;
	return -1;
	}
}

int main()
{
	FILE *fp;

	cout << "open " << "test.txt" << endl;
	system("pause");

	flag = 1;
	//打开源代码文件 

	//未打开 
	if ((fp = fopen("test.txt", "r")) == NULL)
	{
		cout << "Sorry,can't open this file." << endl;
		flag = 0;
	}
	//已打开 
	while (flag == 1)
	{
		//反复调用扫描函数提取单词
		type = Scanner(fp);

		//1:标识符
		if (type > 1000 && type < 2000)
		{
			//cout<<"type:1 identifier      "<<"line "<<line<<" col "<<col-word.length()<<"  "<<word<<endl;
			cout << "(" << word << "," << type - 1000 << ")" << endl;
			if (word.length() > 20)
				cout << "ERROR Identifier length cannot exceed 20 characters" << endl;
			word.clear();
		}
		//2:数字   
		else if (type > 2000)
		{
			//cout<<"type:2 positive number "<<"line "<<line<<" col "<<col-word.length()<<"  "<<word<<endl;
			cout << "(" << word << "," << (type - 2000) << ")" << endl;
			if (word[0] == '0')
				cout << "ERROR: The first digit cannot be 0!" << endl;
			word.clear();
		}
		//3:算数运算符 + - * / 
		else if (type == 3)
		{
			//cout<<"type:3 unary_operator  "<<"line "<<line<<" col "<<col-1<<"  "<<word<<endl;
			cout << "(" << word << "," << "3" << ")" << endl;
			word.clear();
		}

		//4:关系运算符 <、<=、>、>=、= 、<> 
		else if (type == 4)
		{
			//cout<<"type:4 double_operator "<<"line "<<line<<" col "<<col-2<<"  "<<word<<endl;
			cout << "(" << word << "," << "4" << ")" << endl;
			word.clear();
		}
		//6-1+32 - 6-1+32+11:界符
		else if (type >= 37)
		{
			//cout<<"type:5 Separator       "<<"line "<<line<<" col "<<col-1<<"  "<<word<<endl;
			cout << "(" << word << "," << "_" << ")" << endl;
			//cout<<"("<<type<<","<<"_"<<")"<<endl;  
			word.clear();
		}
		//5 - 5-1+32:保留字 
		else if (type >= 5 && type <= 36)
		{
			//cout<<"type:6 reserved word   "<<"line "<<line<<" col "<<col-word.length()<<"  "<<word<<endl;
			cout << "(" << word << "," << "_" << ")" << endl;
			//cout<<"("<<type<<","<<"_"<<")"<<endl;  
			word.clear();
		}
		//非法字符
		else if (type == -1)
		{
			cout << "Illegal character   " << "line " << rows << " cols " << cols - 1 << "  " << word << endl;
			word.clear();
		}
	}
	int a = fclose(fp);
	cout << "Do you want to close?(Y or N)" << endl;
	char end;
	while (cin >> end && end != 'Y') {
		cout << "Do you want to close?(Y or N)" << endl;
	}
	return 0;
}

演算結果:

実験テキスト:

おすすめ

転載: blog.csdn.net/qq_44624536/article/details/113757788