广州大学编译原理-实验一词法分析器

广州大学学生实验报告

开课学院及实验室:计算机科学与工程实验室电子楼412B室          2023年12月19日

学院

计算机科学与网络工程学院

年级、专业、班

****

姓名

***

学号

****

实验课程名称

编译原理实验

成绩

      ***

实验项目名称

词法分析

指导老师

****

一、语法分析——实验目的

通过设计、扩充已有的 C 语言样例中的词法分析内容,为扩展的 C 语言样

例编制并调试一个词法分析程序,从而掌握词法分析程序的构造方法,加深对词

法分析原理的理解。

二、实验环境

(实验使用的软件/硬件环境)win11, dev C++, vs code, vs

三、实验内容及原理

基本实验要求

1) 编码实现将各类编程语言(不仅限指导书中提供的 C 语言样例)源程序

翻译成对应的二元组 TOKEN 序列,并能检查一定的词法错误,要求在

实现的代码上做好详细注释。

2) 编码实现的功能包含对关键字、带下划线的标识符、字符串常量、 注释

的识别,10 或 16 进制的整型常量、带指数的双精度常量的识别,以及

词法错误处理(选做)。

3) 按模板撰写完成详细的实验报告,根据完成的工作量、正确性和代码注

释与实验报告清晰程度综合打分。

探索部分实验要求

(一)依据表示标识符的正规式给出最简 DFA 的状态转换图

输入:表示标识符的正规式(标识符:以字母开头,由字母和数字构成的字符串)

输出:

n 确定化后的 NFA 状态转换图或转换矩阵和初、终态;

n 最简化后的 DFA 状态转换图或状态转换矩阵及初、终态;

编码实现以下功能:

(1) 明确字母表∑中包含的字符,输入表示标识符的正规式,依据等价规则

构造相应的 NFA;(思考 NFA 的状态转换图以什么样的形式来存储)

(2) 编码实现对 NFA 的确定化,生成对应的 DFA;(难点

(3) 编码实现对 DFA 的最简化,并输出其状态转换图。

(二)上传源程序代码图片,识别图中有效字符代码,并按照基础实验

要求完成对代码中不同类型单词的识别和输出

输入:包含源代码的图片(图片格式不限,但必须包含基础实验要求中待识别的

单词对象)

输出:同基础实验要求一样

编码实现以下功能:

(1) 编码识别图中源程序的各项有效代码字符并进行存储,要求不改变代码

原意。

(2) 同基础实验要求一样。

完整代码

#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <set>
using namespace std;

// 单词的类型
enum TokenType
{

    Keywords,
    Identifiers,
    Literals,   // 常数
    Operators,  // 运算符
    Delimiters, // 界符
};

// 结构体 : 包含单词类型, 种别码, 值
struct Token
{
    TokenType tokenType; // 单词类型
    int syn;             // 种别码
    string value;        // 值

    // 构造函数
    Token(TokenType tokenType1, int syn1, string value1)
    {
        this->tokenType = tokenType1;
        this->syn = syn1;
        this->value = value1;
    }

    Token() {}
};

vector<Token> ans; // 二元组结果
vector<string> ans_error;
vector<string> keywords = {
    "main", "int", "char", "if", "else", "for", "while", "return", "void"}; // 保留字

// 种别码

map<string, int> getSyn = {
    {"main", 1},
    {"int", 2},
    {"char", 3},
    {"if", 4},
    {"else", 5},
    {"for", 6},
    {"while", 7},
    {"return", 8},
    {"void", 9},
    {"string", 50},
    {"id", 10},
    {"num", 20},
    {"=", 21},
    {"+", 22},
    {"-", 23},
    {"*", 24},
    {"“", 11},

    // 第二列
    {"/", 25},
    {"(", 26},
    {")", 27},
    {"[", 28},
    {"]", 29},
    {"{", 30},
    {"}", 31},
    {",", 32},
    {":", 33},
    {";", 34},
    {">", 35},
    {"<", 36},
    {">=", 37},
    {"<=", 38},
    {"==", 39},
    {"!=", 40},
    {"”", 12},
};

bool isKeyWord(string s)
{
    int n = keywords.size();
    for (int i = 0; i < n; i++)
    {
        if (s == keywords[i])
        {
            return true;
        }
    }
    return false;
}

void tokenize(string sourceCode)
{
    int n = sourceCode.size();
    for (int i = 0; i < n; i++)
    {

        char ch = sourceCode[i];

        // 字母 : 保留字或者标识符
        // 字母开头或者_下划线开头
        if (isalpha(ch) || ch == '_')
        {
            string currentToken = ""; // 当前单词

            while (i < n && (isdigit(sourceCode[i]) || isalpha(sourceCode[i]) || sourceCode[i] == '_'))
            {
                currentToken += sourceCode[i];
                i++;
            }

            // 遇到了其他字符(空格, “”, 或者其他())
            // 查询是否是保留字
            if (isKeyWord(currentToken))
            {
                Token token;
                token.tokenType = Keywords;
                token.syn = getSyn[currentToken];
                token.value = currentToken;
                ans.push_back(token);
            }
            // 标识符
            else
            {
                Token token;
                token.tokenType = Identifiers;
                token.syn = getSyn["id"]; // id的种别码
                token.value = currentToken;
                ans.push_back(token);
            }
            i--;
        }

        // 数字
        // 添加功能 : 小数点
        else if (isdigit(ch))
        {
            string currentToken = "";
            int j;
            set<char> st; // 记录 小数点, e, E的出现次数;
            for (j = i; j < n; j++)
            {

                // 数字
                if (isdigit(sourceCode[j]))
                {
                    currentToken += sourceCode[j];
                }
                // 小数点
                else if (sourceCode[j] == '.')
                {
                    // 第一次出现小数点
                    if (!st.count('.'))
                    {
                        st.insert('.');
                        currentToken += sourceCode[j];
                    }
                    else
                    {
                        ans_error.push_back("错误, 浮点数出现了两个小数点.");
                    }
                }
                // 字母e和字母E
                else if (sourceCode[j] == 'e' || sourceCode[j] == 'E')
                {
                    // 第一次出现e
                    if (!st.count(sourceCode[j]))
                    {
                        st.insert(sourceCode[j]);
                        currentToken += sourceCode[j];
                    }
                    else
                    {
                        ans_error.push_back("错误, 科学记数法出现了两个e或者E.");
                    }
                }

                // e后面有+和-
                else if (sourceCode[j] == '+' || sourceCode[j] == '-')
                {
                    // 第一次出现这个
                    if (!st.count(sourceCode[j]) && (sourceCode[j - 1] == 'e' || sourceCode[j - 1] == 'E'))
                    {
                        st.insert(sourceCode[j]);
                        currentToken += sourceCode[j];
                    }
                    else
                    {
                        ans_error.push_back("错误, 科学记数法中 : + 或者 -出现问题, (重复出现或者前面没有e或者E)");
                    }
                }

                else
                {
                    break;
                }
            }

            Token token;
            token.tokenType = Literals;
            token.syn = getSyn["num"];
            token.value = currentToken;
            ans.push_back(token);

            i = j - 1;
        }

        // 加号 +
        else if (ch == '+')
        {
            Token token;
            token.tokenType = Operators;
            token.syn = getSyn["+"];
            token.value = "+";
            ans.push_back(token);
        }

        // 减号
        else if (ch == '-')
        {
            Token token;
            token.tokenType = Operators;
            token.syn = getSyn["-"];
            token.value = "-";
            ans.push_back(token);
        }

        // 乘号
        else if (ch == '*')
        {
            Token token;
            token.tokenType = Operators;
            token.syn = getSyn["*"];
            token.value = "*";
            ans.push_back(token);
        }

        // 小于 或者 小于等于
        if (ch == '<')
        {
            if (sourceCode[i + 1] == '=')
            {
                string currentToken = "<=";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["<="];
                token.value = "<=";
                ans.push_back(token);
                i++;
            }
            else
            {
                string currentToken = "<";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["<"];
                token.value = "<";
                ans.push_back(token);
            }
        }

        // 大于 或者 大于等于
        if (ch == '>')
        {
            if (sourceCode[i + 1] == '=')
            {
                string currentToken = ">=";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn[">="];
                token.value = ">=";
                ans.push_back(token);
                i++;
            }
            else
            {
                string currentToken = ">";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn[">"];
                token.value = ">";
                ans.push_back(token);
            }
        }

        //= 或者 ==
        if (ch == '=')
        {
            if (sourceCode[i + 1] == '=')
            {
                string currentToken = "==";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["=="];
                token.value = "==";
                ans.push_back(token);
                i++;
            }
            else
            {
                string currentToken = "=";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["="];
                token.value = "=";
                ans.push_back(token);
            }
        }

        // 分号
        if (ch == ';')
        {
            Token token;
            token.tokenType = Delimiters;
            token.syn = getSyn[";"];
            // token.value = "" + ch; //不能直接拼接
            token.value = ";";

            ans.push_back(token);
        }

        // 字符串常量 : 双引号
        else if (ch == '"')
        {
            Token tokenLeft(Delimiters, getSyn["\""], "\"");
            ans.push_back(tokenLeft); // 双引号

            bool contain = false;
            int j = i + 1;
            for (j = i + 1; j < n; j++)
            {
                if (sourceCode[j] == '"')
                {
                    contain = true;
                    break;
                }
            }

            //""不成对出现
            if (contain == false)
            {
                string s = "编译错误, 双引号\"\"缺失, 没有成对出现";
                ans_error.push_back(s);
            }
            else
            {
                string currentToken = sourceCode.substr(i + 1, (j - 1) - (i + 1) + 1);
                Token token;
                token.tokenType = Literals;
                token.syn = getSyn["string"];
                token.value = currentToken;

                ans.push_back(token);
                Token tokenRight(Delimiters, getSyn["\""], "\""); // 双引号
                ans.push_back(tokenRight);                        // 双引号

                i = j;
            }
        }

        // ()
        else if (ch == '(' || ch == ')')
        {

            if (ch == '(')
            {
                Token tokenLeft(Delimiters, getSyn["("], "(");
                ans.push_back(tokenLeft); // 双引号
                bool contain = false;
                int j = i + 1;
                for (j = i + 1; j < n; j++)
                {
                    if (sourceCode[j] == ')')
                    {
                        contain = true;
                        break;
                    }
                }
                //""不成对出现
                if (contain == false)
                {
                    string s = "编译错误, 括号)缺失, 没有成对出现";
                    ans_error.push_back(s);
                }
            }

            // 右括号
            else
            {
                Token tokenLeft(Delimiters, getSyn[")"], ")");
                ans.push_back(tokenLeft); // 双引号
            }
        }

        // []
        else if (ch == '[' || ch == ']')
        {

            if (ch == '[')
            {
                Token tokenLeft(Delimiters, getSyn["["], "[");
                ans.push_back(tokenLeft); // 双引号
                bool contain = false;
                int j = i + 1;
                for (j = i + 1; j < n; j++)
                {
                    if (sourceCode[j] == ']')
                    {
                        contain = true;
                        break;
                    }
                }
                //""不成对出现
                if (contain == false)
                {
                    string s = "编译错误, 中括号 ] 缺失, 没有成对出现";
                    ans_error.push_back(s);
                }
            }

            // 右括号
            else
            {
                Token tokenLeft(Delimiters, getSyn["]"], "]");
                ans.push_back(tokenLeft); // 双引号
            }
        }

        // {}
        else if (ch == '{' || ch == '}')
        {

            if (ch == '{')
            {
                Token tokenLeft(Delimiters, getSyn["{"], "{");
                ans.push_back(tokenLeft); // 双引号
                bool contain = false;
                int j = i + 1;
                for (j = i + 1; j < n; j++)
                {
                    if (sourceCode[j] == '}')
                    {
                        contain = true;
                        break;
                    }
                }
                //""不成对出现
                if (contain == false)
                {
                    string s = "编译错误, 大括号 } 缺失, 没有成对出现";
                    ans_error.push_back(s);
                }
            }

            // 右括号
            else
            {
                Token tokenLeft(Delimiters, getSyn["}"], "}");
                ans.push_back(tokenLeft); // 双引号
            }
        }

        // 冒号
        else if (ch == ':')
        {
            Token token;
            token.tokenType = Delimiters;
            token.syn = getSyn[":"];
            token.value = ":";

            ans.push_back(token);
        }

        // 叹号
        else if (ch == '!')
        {
            if (sourceCode[i + 1] == '=')
            {
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["!="];
                token.value = "!=";
                ans.push_back(token);
                i++;
            }

            else
            {
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["!"];
                token.value = "!";
                ans.push_back(token);
            }
        }

        // 点 .
        else if (ch == '.')
        {
            Token token;
            token.tokenType = Operators;
            token.syn = getSyn["."];
            token.value = ".";
            ans.push_back(token);
        }

        // 除号/ 注释
        else if (ch == '/')
        {
            // 注释1 : //
            if (sourceCode[i + 1] == '/')
            {
                int j = i + 2;
                string s = "//";
                while (j < n && sourceCode[j] != '\n')
                {
                    s += sourceCode[j];
                    j++;
                }

                i = j;
                Token token;
                token.tokenType = Literals;
                token.value = s;
                ans.push_back(token);
            }
            // 注释2 : / *  * /
            else if (sourceCode[i + 1] == '*')
            {
                int j = i + 2;
                while (j + 1 < n && !(sourceCode[j] == '*' && sourceCode[j + 1] == '/'))
                {
                    j++;
                }

                // /* 成对出现  : 正常
                if (sourceCode[j] == '*' && sourceCode[j + 1] == '/')
                {
                    string s = "/*" + sourceCode.substr(i + 2, j - 1 - (i + 2) + 1) + "*/";
                    Token token;
                    token.tokenType = Literals;
                    token.value = s;
                    ans.push_back(token);
                    i = j + 1;
                }
                else
                {
                    ans_error.push_back("编译错误, /* 注释符号不成对出现");
                }
            }
            // 普通除号
            else
            {
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["/"];
                token.value = "/";

                ans.push_back(token);
            }
        }
    }
}
int main()
{

    // 打开文件
    cout << "正在打开文件... ..." << endl;
    fstream file("source_code.c");
    // fstream file("imgToCode.c");
    string sourceCode = "";
    if (!file.is_open())
    {
        cout << "打开文件失败" << endl;
    }
    else
    {
        cout << "打开文件成功" << endl;

        string buf;
        while (getline(file, buf))
        {
            buf = "\n" + buf;
            sourceCode += buf;
        }
    }

    // 读取文件的内容
    cout << "源程序的代码是 : " << endl;
    cout << sourceCode << endl;

    // 编译中
    tokenize(sourceCode);

    if (ans_error.size() == 0)
    {
        cout << "编译成功" << endl;
        for (auto token : ans)
        {
            cout << "( " << token.syn << " : " << token.value << " )" << endl;
        }
    }
    else {
        cout << "编译失败" << endl;
        for(auto s : ans_error) 
        cout << s << endl;
    }
}

四、关键数据结构和核心算法

4.1 数据结构

单词的类型 : 枚举类

结构体 : 包含单词类型, 种别码, 值


// 单词的类型
enum TokenType
{

    Keywords,
    Identifiers,
    Literals,   // 常数
    Operators,  // 运算符
    Delimiters, // 界符
};

// 结构体 : 包含单词类型, 种别码, 
struct Token
{
    TokenType tokenType; // 单词类型
    int syn;             // 种别码
    string value;        // 

    // 构造函数
    Token(TokenType tokenType1, int syn1, string value1)
    {
        this->tokenType = tokenType1;
        this->syn = syn1;
        this->value = value1;
    }

    Token() {}
};

  1. 2 核心算法


void tokenize(string sourceCode)
{
    int n = sourceCode.size();
    for (int i = 0; i < n; i++)
    {

        char ch = sourceCode[i];

        // 字母  保留字或者标识符
        // 字母开头或者_下划线开头
        if (isalpha(ch) || ch == '_')
        {
            string currentToken = ""; // 当前单词

            while (i < n && (isdigit(sourceCode[i]) || isalpha(sourceCode[i]) || sourceCode[i] == '_'))
            {
                currentToken += sourceCode[i];
                i++;
            }

            // 遇到了其他字符(空格, “”, 或者其他())
            // 查询是否是保留字
            if (isKeyWord(currentToken))
            {
                Token token;
                token.tokenType = Keywords;
                token.syn = getSyn[currentToken];
                token.value = currentToken;
                ans.push_back(token);
            }
            // 标识符
            else
            {
                Token token;
                token.tokenType = Identifiers;
                token.syn = getSyn["id"]; // id的种别码
                token.value = currentToken;
                ans.push_back(token);
            }
            i--;
        }

        // 数字
        // 添加功能 : 小数点
        else if (isdigit(ch))
        {
            string currentToken = "";
            int j;
            set<char> st; // 记录 小数点, e, E的出现次数;
            for (j = i; j < n; j++)
            {

                // 数字
                if (isdigit(sourceCode[j]))
                {
                    currentToken += sourceCode[j];
                }
                // 小数点
                else if (sourceCode[j] == '.')
                {
                    // 第一次出现小数点
                    if (!st.count('.'))
                    {
                        st.insert('.');
                        currentToken += sourceCode[j];
                    }
                    else
                    {
                        ans_error.push_back("错误, 浮点数出现了两个小数点.");
                    }
                }
                // 字母e和字母E
                else if (sourceCode[j] == 'e' || sourceCode[j] == 'E')
                {
                    // 第一次出现e
                    if (!st.count(sourceCode[j]))
                    {
                        st.insert(sourceCode[j]);
                        currentToken += sourceCode[j];
                    }
                    else
                    {
                        ans_error.push_back("错误, 科学记数法出现了两个e或者E.");
                    }
                }

                // e后面有+和-
                else if (sourceCode[j] == '+' || sourceCode[j] == '-')
                {
                    // 第一次出现这个
                    if (!st.count(sourceCode[j]) && (sourceCode[j - 1] == 'e' || sourceCode[j - 1] == 'E'))
                    {
                        st.insert(sourceCode[j]);
                        currentToken += sourceCode[j];
                    }
                    else
                    {
                        ans_error.push_back("错误, 科学记数法中 : + 或者 -出现问题, (重复出现或者前面没有e或者E)");
                    }
                }

                else
                {
                    break;
                }
            }

            Token token;
            token.tokenType = Literals;
            token.syn = getSyn["num"];
            token.value = currentToken;
            ans.push_back(token);

            i = j - 1;
        }

        // 加号 +
        else if (ch == '+')
        {
            Token token;
            token.tokenType = Operators;
            token.syn = getSyn["+"];
            token.value = "+";
            ans.push_back(token);
        }

        // 减号
        else if (ch == '-')
        {
            Token token;
            token.tokenType = Operators;
            token.syn = getSyn["-"];
            token.value = "-";
            ans.push_back(token);
        }

        // 乘号
        else if (ch == '*')
        {
            Token token;
            token.tokenType = Operators;
            token.syn = getSyn["*"];
            token.value = "*";
            ans.push_back(token);
        }

        // 小于 或者 小于等于
        if (ch == '<')
        {
            if (sourceCode[i + 1] == '=')
            {
                string currentToken = "<=";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["<="];
                token.value = "<=";
                ans.push_back(token);
                i++;
            }
            else
            {
                string currentToken = "<";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["<"];
                token.value = "<";
                ans.push_back(token);
            }
        }

        // 大于 或者 大于等于
        if (ch == '>')
        {
            if (sourceCode[i + 1] == '=')
            {
                string currentToken = ">=";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn[">="];
                token.value = ">=";
                ans.push_back(token);
                i++;
            }
            else
            {
                string currentToken = ">";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn[">"];
                token.value = ">";
                ans.push_back(token);
            }
        }

        //= 或者 ==
        if (ch == '=')
        {
            if (sourceCode[i + 1] == '=')
            {
                string currentToken = "==";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["=="];
                token.value = "==";
                ans.push_back(token);
                i++;
            }
            else
            {
                string currentToken = "=";
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["="];
                token.value = "=";
                ans.push_back(token);
            }
        }

        // 分号
        if (ch == ';')
        {
            Token token;
            token.tokenType = Delimiters;
            token.syn = getSyn[";"];
            // token.value = "" + ch; //不能直接拼接
            token.value = ";";

            ans.push_back(token);
        }

        // 字符串常量 : 双引号
        else if (ch == '"')
        {
            Token tokenLeft(Delimiters, getSyn["\""], "\"");
            ans.push_back(tokenLeft); // 双引号

            bool contain = false;
            int j = i + 1;
            for (j = i + 1; j < n; j++)
            {
                if (sourceCode[j] == '"')
                {
                    contain = true;
                    break;
                }
            }

            //""不成对出现
            if (contain == false)
            {
                string s = "编译错误, 双引号\"\"缺失, 没有成对出现";
                ans_error.push_back(s);
            }
            else
            {
                string currentToken = sourceCode.substr(i + 1, (j - 1) - (i + 1) + 1);
                Token token;
                token.tokenType = Literals;
                token.syn = getSyn["string"];
                token.value = currentToken;

                ans.push_back(token);
                Token tokenRight(Delimiters, getSyn["\""], "\""); // 双引号
                ans.push_back(tokenRight);                        // 双引号

                i = j;
            }
        }

        // ()
        else if (ch == '(' || ch == ')')
        {

            if (ch == '(')
            {
                Token tokenLeft(Delimiters, getSyn["("], "(");
                ans.push_back(tokenLeft); // 双引号
                bool contain = false;
                int j = i + 1;
                for (j = i + 1; j < n; j++)
                {
                    if (sourceCode[j] == ')')
                    {
                        contain = true;
                        break;
                    }
                }
                //""不成对出现
                if (contain == false)
                {
                    string s = "编译错误, 括号)缺失, 没有成对出现";
                    ans_error.push_back(s);
                }
            }

            // 右括号
            else
            {
                Token tokenLeft(Delimiters, getSyn[")"], ")");
                ans.push_back(tokenLeft); // 双引号
            }
        }

        // []
        else if (ch == '[' || ch == ']')
        {

            if (ch == '[')
            {
                Token tokenLeft(Delimiters, getSyn["["], "[");
                ans.push_back(tokenLeft); // 双引号
                bool contain = false;
                int j = i + 1;
                for (j = i + 1; j < n; j++)
                {
                    if (sourceCode[j] == ']')
                    {
                        contain = true;
                        break;
                    }
                }
                //""不成对出现
                if (contain == false)
                {
                    string s = "编译错误, 中括号 ] 缺失, 没有成对出现";
                    ans_error.push_back(s);
                }
            }

            // 右括号
            else
            {
                Token tokenLeft(Delimiters, getSyn["]"], "]");
                ans.push_back(tokenLeft); // 双引号
            }
        }

        // {}
        else if (ch == '{' || ch == '}')
        {

            if (ch == '{')
            {
                Token tokenLeft(Delimiters, getSyn["{"], "{");
                ans.push_back(tokenLeft); // 双引号
                bool contain = false;
                int j = i + 1;
                for (j = i + 1; j < n; j++)
                {
                    if (sourceCode[j] == '}')
                    {
                        contain = true;
                        break;
                    }
                }
                //""不成对出现
                if (contain == false)
                {
                    string s = "编译错误, 大括号 } 缺失, 没有成对出现";
                    ans_error.push_back(s);
                }
            }

            // 右括号
            else
            {
                Token tokenLeft(Delimiters, getSyn["}"], "}");
                ans.push_back(tokenLeft); // 双引号
            }
        }

        // 冒号
        else if (ch == ':')
        {
            Token token;
            token.tokenType = Delimiters;
            token.syn = getSyn[":"];
            token.value = ":";

            ans.push_back(token);
        }

        // 叹号
        else if (ch == '!')
        {
            if (sourceCode[i + 1] == '=')
            {
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["!="];
                token.value = "!=";
                ans.push_back(token);
                i++;
            }

            else
            {
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["!"];
                token.value = "!";
                ans.push_back(token);
            }
        }

        //  .
        else if (ch == '.')
        {
            Token token;
            token.tokenType = Operators;
            token.syn = getSyn["."];
            token.value = ".";
            ans.push_back(token);
        }

        // 除号/ 注释
        else if (ch == '/')
        {
            // 注释1 : //
            if (sourceCode[i + 1] == '/')
            {
                int j = i + 2;
                string s = "//";
                while (j < n && sourceCode[j] != '\n')
                {
                    s += sourceCode[j];
                    j++;
                }

                i = j;
                Token token;
                token.tokenType = Literals;
                token.value = s;
                ans.push_back(token);
            }
            // 注释2 : / *  * /
            else if (sourceCode[i + 1] == '*')
            {
                int j = i + 2;
                while (j + 1 < n && !(sourceCode[j] == '*' && sourceCode[j + 1] == '/'))
                {
                    j++;
                }

                // /* 成对出现  : 正常
                if (sourceCode[j] == '*' && sourceCode[j + 1] == '/')
                {
                    string s = "/*" + sourceCode.substr(i + 2, j - 1 - (i + 2) + 1) + "*/";
                    Token token;
                    token.tokenType = Literals;
                    token.value = s;
                    ans.push_back(token);
                    i = j + 1;
                }
                else
                {
                    ans_error.push_back("编译错误, /* 注释符号不成对出现");
                }
            }
            // 普通除号
            else
            {
                Token token;
                token.tokenType = Operators;
                token.syn = getSyn["/"];
                token.value = "/";

                ans.push_back(token);
            }
        }
    }
}

python图像识别 :

import pytesseract
from PIL import Image
# 识别图片
image = Image.open('img.png')
code = pytesseract.image_to_string(image, lang='eng')

print(code)
# 将识别出来的代码写入文件
file = open("E:\code\Complilers\\test1\imgToCode.c", "w")
file.write(code)

4.3 错误处理

4.4 运行结果

五、总结

实现了一个词法分析器

  1. 对输入源程序字符串进行词法分析,输出二元组序列,包括对以下字符的分析
    1. 关键字
    2. 带下划线的标识符
    3. 字符串常量
    4. 注释
    5. 科学计数法
  2. 实现OCR图像, 能够对图像形式的c程序代码, 进行识别得到源程序字符串, 并对其进行分析.

  • 36
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值