目的:
単語読み取りプロセスをコンパイルします。入力ソースプログラムから、独立した意味を持つ単語、つまり、基本的な予約語、識別子、定数、演算子、および区切り文字の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;
}