编译原理——词法分析器

1 概述

设计、编制并调试一个简单的C语言词法分析程序,掌握利用状态转换图设计词法分析器的基本方法,利用该词法分析器完成对源程序字符串的词法分析。通过对该词法分析器的设计,加深对词法分析原理、状态转换图等编译原理知识的理解。

2 使用的基本概念和原理

词法分析器读取的主要功能是输入源程序,输出单词符号,对源程序从左到右,从上到下对逐个字符进行扫描,把把构成源程序的字符串转换成单词符号的序列,输出单词序列用于语法分析。同时还可以滤掉空格、换行符、注释、行列计数,发现错误等功能。语法分析中单词符号主要分为:关键字、标识符、常数、运算符、界符5类,词法分析器可作为独立的一遍,也可作为语法分析器的子程序。

NFA与DFA转换

可以用子集法将NFA转换为DFA,再利用分割法将DFA最小化,正规式的整体变换如图所示:

3 总体设计

词法分析器首先将输入的文件进行读取,读取后对源程序的字符调用词法分析程序分析,根据字符种类来确定调用函数,将结果进行保存,随后输出,主程序示意图如图所示:

 程序在调用词法分析器进行词法分析,根据类码表进行分析,词法分析程序框图如图所示

词法分析器的功能输入源程序,按照构词规则分解成一系列单词符号。单词是语言中具有独立意义的最小单位,包括关键字、标识符、运算符、界符和常数等,本课程设计的数据定义表如表所示:

表 部分单词符号及其分类码表

单词符号

类别编码

类别码的助记符号

单词值

begin

1

BEGIN

关键字

end

2

END

if

3

IF

else

4

ELSE

return

5

RETURN

while

6

WHILE

then

7

THEN

for

8

FOR

int

9

INT

char

10

CHAR

float

11

FLOAE

main

12

MAIN

cin

13

CIN

cout

14

COUT

标识符

15

BA

字母数字串

常数(0-9)

16

CA

数字串

运算符

(+、-、*、%、<、>、=、!)

17

DA

数学运算符号

界符

(; , { } [ ]  ( ) :))

18

EA

分隔符号

4 代码实现

/*************Written By WFP************/
   /*******Date : 12,16,2022********/
#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <iomanip>

using namespace std;
string KEYWORD[100] = { "begin","end", "if","else","return","while","then","for",      //关键字
                    "int","char","float","main","cin","cout" };
char SEPARATER[50] = { ';',',','{','}','[',']','(',')',':' };    //界符
char OPERATOR[50] = { '+','-','*','/','>','<','=','!','%'};     //运算符
char FILTER[10] = { ' ','\n','\t'};                    //过滤符
const int IDENTIFIER = 100;         //标识符值
const int CONSTANT = 101;           //常数值
const int FILTER_VALUE = 102;
/**判断是否为关键字**/
int l = 1, a = 0;
bool IsKeyword(string word) {
    for (int i = 0; i < 18; i++) {
        if (KEYWORD[i] == word) {
            if (KEYWORD[i] == "begin")
                printf("助记符号:BEGIN\t");
            if (KEYWORD[i] == "end")
                printf("助记符号:END\t");
            if (KEYWORD[i] == "if")
                printf("助记符号:IF\t");
            if (KEYWORD[i] == "else")
                printf("助记符号:ELSE\t");
            if (KEYWORD[i] == "while")
                printf("助记符号:WHILE\t");
            if (KEYWORD[i] == "int")
                printf("助记符号:INT\t");
            if (KEYWORD[i] == "char")
                printf("助记符号:CHAR\t");
            if (KEYWORD[i] == "for")
                printf("助记符号:FOR\t");
            if (KEYWORD[i] == "return")
                printf("助记符号:RETURN");
            if (KEYWORD[i] == "cout")
                printf("助记符号:COUT\t");
            if (KEYWORD[i] == "float")
                printf("助记符号:FLOAT\t");
            if (KEYWORD[i] == "main")
                printf("助记符号:MAIN\t");
            if (KEYWORD[i] == "cin")
                printf("助记符号:CIN\t");
            if (KEYWORD[i] == "then")
                printf("助记符号:THEN\t");
            a++;
            return true;
        }
    }
    return false;
}
/**判断是否为界符**/
int b = 0;
bool IsSeparater(char ch) {
    for (int i = 0; i < 10; i++) {
        if (SEPARATER[i] == ch) {
            return true;
        }
    }
    return false;
}

/**判断是否为运算符**/
int c = 0;
bool IsOperator(char ch) {
    for (int i = 0; i < 10; i++) {
        if (OPERATOR[i] == ch) {
            return true;
        }
    }
    return false;
}
/**判断是否为过滤符**/
bool IsFilter(char ch) {
    for (int i = 0; i < 4; i++) {
        if (FILTER[i] == ch) {
            if(ch=='\n')
                l++;
            return true;
        }
    }
    return false;
}
/**判断是否为大写字母**/
int e = 0;
bool IsUpLetter(char ch) {
    if (ch >= 'A' && ch <= 'Z') return true;
    return false;
}
/**判断是否为小写字母**/

bool IsLowLetter(char ch) {
    if (ch >= 'a' && ch <= 'z') return true;
    return false;
}
/**判断是否为常数**/
int f = 0;
bool IsDigit(char ch) {
    if (ch >= '0' && ch <= '9') return true;
    return false;
}

template <class T>
int value(T* a, int n, T str) {
    for (int i = 0; i < n; i++) {
        if (a[i] == str) return i + 1;
    }
    return -1;
}
int g = 0;
int h = 0;
int i = 0;
/**词法分析**/



void analyse(FILE* fpin) {
    char ch = ' ';
    string arr = "";
    
    while ((ch = fgetc(fpin)) != EOF) {
        
        arr = "";
        
        if (IsFilter(ch)) {/*while (IsFilter(ch)) {
            arr += ch;
            if (ch == '\n') {
                l++;
                }
            ch = fgetc(fpin);
            }*/
            if(ch!=' ')
                printf("*********************第%d行*********************\n", l);
        }              //判断是否为过滤符
        
        else if (IsLowLetter(ch)) {       //判断是否为关键字
            while (IsLowLetter(ch)) {
                arr += ch;
                ch = fgetc(fpin);
            }
            //fseek(fpin,-1L,SEEK_CUR);
            if (IsKeyword(arr)) {
                printf("类别编码:%d\t", value(KEYWORD, 100, arr));
                //cout << arr  << "  关键字" << endl;
                //if(IaKeyword(arr))
                cout << "文件中符号:" << arr << " 单词类型:" << "关键字" << endl;
                //printf("第%d行\t", l);
                
            }
            else
            {
                printf("助记符号:BA\t");
                printf("类别编码:15\t");
                //cout << arr << "  标识符" << endl;
                cout << "文件中符号:" << arr << " 单词类型:" << "标识符" << endl;
                //printf("第%d行\t", l);
                e++;
            }
            
        }
        
        else if (IsDigit(ch)) {           //判断是否为常数
            while (IsDigit(ch) || (ch == '.' && IsDigit(fgetc(fpin)))) {
                arr += ch;
                printf("助记符号:CA\t");
                
                ch = fgetc(fpin);
            }
            fseek(fpin, -1L, SEEK_CUR);
            printf("类别编码:16\t");
            //cout << arr << "  整形数" <<endl;
            cout << "文件中符号:" << arr << " 单词类型:" << "常数" << endl;
            //printf("第%d行\t", l);
            f++;
        }
        else if (IsUpLetter(ch) || IsLowLetter(ch) || ch == '_') {
            while (IsUpLetter(ch) || IsLowLetter(ch) || ch == '_' || IsDigit(ch)) {
                arr += ch;
                ch = fgetc(fpin);
            }
            fseek(fpin, -1L, SEEK_CUR);
            printf("类别编码:15\t");
            //cout << arr << "  标识符" << endl;
            cout << "文件中符号:" << arr <<" 单词类型:" << "标识符" << endl;
            //printf("第%d行\t", l);
            e++;
        }
        else if (IsOperator(ch)||ch== '/') {
            arr += ch;
            if (ch == '*')
            {
                arr += ch;
                ch = fgetc(fpin);
                while (ch != '*') {
                    arr += ch;
                    ch = fgetc(fpin);
                    if (ch == '*') {
                        arr += ch;
                        ch = fgetc(fpin);
                        if (ch == '/') {
                            i++;
                            break;

                        }
                    }

                }

            }
            else if (ch == '/') {
                arr += ch;
                ch = fgetc(fpin);
                while (ch != '\n') {
                    arr += ch;
                    ch = fgetc(fpin);
                    if (ch == ' ') {
                        i++;
                        break;
                    }
                        
                    }
                
                
            }
            else {
                printf("助记符号:DA\t");
                printf("类别编码:17\t");
                //cout << arr << "  运算符" << endl;
                cout << "文件中符号:" << arr << " 单词类型:" << "运算符" << endl;
                //printf("第%d行\t", l);
                c++;
            }

        }
        //else if()
        else switch (ch) {
        case '+':
        case '-':
        case '*':
        case '/':
        case '>':
        case '<':
        case '=':
        case '!':
        
        {
            arr += ch;
            
            printf("助记符号:DA\t");
            printf("类别编码:17\t");
            //cout << arr << "  运算符" << endl;
            cout << "文件中符号:" << arr << " 单词类型:" << "运算符" << endl;
            //printf("第%d行\t", l);
            c++;
            break;
        }
        case ';':
        case ',':
        case '(':
        case ')':
        case '[':
        case ']':
        case '{':
        case '}':
        case ':':
        {
            arr += ch;
            
            printf("助记符号:EA\t");
            
            printf("类别编码:18\t");
            cout << "文件中符号:" << arr << " 单词类型:"<< "界符" << endl;
            //printf("第%d行\t", l);
            b++;
            break;
        }
        
        default:cout << "\"" << ch << "\":无法识别的字符!" << endl;
            g++;
        }
        
    }
    h = a + b + c + e + f + g;
    printf("文件内容一共有 %d 行\n", l);
    printf("一共有 %d 个字符\n", h);
    printf("基本保留字一共有 %d 个\n", a);
    printf("界符一共有 %d 个\n", b);
    printf("运算符一共有 %d 个\n", c);
    printf("标识符一共有 %d 个\n", e);
    printf("常数一共有 %d 个\n", f);
    printf("注释共有 %d 处\n", i);
    printf("错误共有 %d 个\n", g);

}









int main()
{
    char inFile[40];
    FILE* fpin;
    cout << "请输入源文件名(包括路径和后缀):";
    while (true) {
        cin >> inFile;
        if ((fpin = fopen(inFile, "r")) != NULL)
            break;
        else {
            cout << "文件名错误!" << endl;
            cout << "请输入源文件名(包括路径和后缀):";
        }

    }
    /*char ch = ' ';
    while ((ch = fgetc(fpin)) != EOF) {
        printf("%c", ch);
    }*/
    cout << "------词法分析如下------" << endl;
    cout << "*********************第1行*********************" << endl;
    //read(fpin);
    analyse(fpin);

    system("pause");
    return 0;
    

}

测试和试运行

程序测试

进行测试文件编写,采用txt文件,程序内容如下所示:

int main (){

int a=1,b=2;

b / a;

b >a;

c=a +b;

cout <<c;return 0;int

}

通过对程序进行调试,调试控制台如图所示:

 

输入文件路径并运行,如图所示:

 

 

 

源码地址: https://github.com/wen3017/word-analyse/blob/analyse/word.cpp

课设文件需要留言

  • 28
    点赞
  • 208
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值