Compiler Lab1- 自制词法分析器

news2024/11/25 16:25:57

由于编译原理课的Lab1为自制词法分析器,所以笔者用C++实现了一个极简的C语言词法分析器,用于分析C语言源代码。它可以处理关键字、标识符、整数、实数、浮点数的科学计数法表示、运算符、分隔符、字符串字面量、字符字面量、注释和预处理指令。请注意,此版本的词法分析器不是很完善,但它应该能够处理大多数简单的C语言源代码。

用户输入输入文件名和输出文件名,然后检查这些文件是否可以正确打开。然后,我们从输入文件中读取内容,对其进行词法分析,并将结果写入输出文件中。最后,我们通知用户词法分析已完成,并提示用户查看输出文件以获取结果。

mylexer.cpp文件 

词法分析器核心文件

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <unordered_set>

using namespace std;

enum class TokenType
{
    Keyword,
    Identifier,
    Integer,
    Real,
    Operator,
    Separator,
    StringLiteral,
    CharLiteral,
    Comment,
    Preprocessor,
    Unknown
};

struct Token
{
    TokenType type;
    string value;
};

bool isKeyword(const string &value)
{
    static const unordered_set<string> keywords = {
        "auto", "break", "case", "char", "const", "continue", "default", "do",
        "double", "else", "enum", "extern", "float", "for", "goto", "if", "int",
        "long", "register", "return", "short", "signed", "sizeof", "static",
        "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while"};
    return keywords.find(value) != keywords.end();
}

bool isOperator(char c)
{
    static const unordered_set<char> operators = {
        '+', '-', '*', '/', '%', '>', '<', '=', '&', '|', '!', '~', '^', '?', ':'};
    return operators.find(c) != operators.end();
}

bool isSeparator(char c)
{
    static const unordered_set<char> separators = {
        '(', ')', '[', ']', '{', '}', ',', ';', '.', '#'};
    return separators.find(c) != separators.end();
}

vector<Token> lex(const string &input)
{
    vector<Token> tokens;
    string buffer;

    auto flushBuffer = [&]()
    {
        if (!buffer.empty())
        {
            if (isKeyword(buffer))
            {
                tokens.push_back({TokenType::Keyword, buffer});
            }
            else
            {
                tokens.push_back({TokenType::Identifier, buffer});
            }
            buffer.clear();
        }
    };

    size_t i = 0;
    while (i < input.length())
    {
        char c = input[i];

        if (isalpha(c) || c == '_')
        {
            buffer.push_back(c);
            i++;
        }
        else
        {
            flushBuffer();

            if (isdigit(c))
            {
                string number;
                number.push_back(c);
                i++;
                while (i < input.length() && (isdigit(input[i]) || input[i] == '.' || tolower(input[i]) == 'e'))
                {
                    number.push_back(input[i]);
                    if (tolower(input[i]) == 'e' && i + 1 < input.length() && (input[i + 1] == '+' || input[i + 1] == '-'))
                    {
                        number.push_back(input[++i]);
                    }
                    i++;
                }
                while (i < input.length() && (tolower(input[i]) == 'u' || tolower(input[i]) == 'l'))
                {
                    number.push_back(input[i]);
                    i++;
                }
                tokens.push_back({number.find('.') != string::npos || number.find('e') != string::npos || number.find('E') != string::npos ? TokenType::Real : TokenType::Integer, number});
            }
            else if (isOperator(c))
            {
                if (c == '/' && i + 1 < input.length())
                {
                    if (input[i + 1] == '/')
                    {
                        i += 2;
                        string comment;
                        while (i < input.length() && input[i] != '\n')
                        {
                            comment.push_back(input[i]);
                            i++;
                        }
                        tokens.push_back({TokenType::Comment, comment});
                    }
                    else if (input[i + 1] == '*')
                    {
                        i += 2;
                        string comment;
                        while (i + 1 < input.length() && !(input[i] == '*' && input[i + 1] == '/'))
                        {
                            comment.push_back(input[i]);
                            i++;
                        }
                        if (i + 1 < input.length())
                        {
                            // comment.push_back(input[i]);
                            i += 2;
                        }
                        tokens.push_back({TokenType::Comment, comment});
                        // cout << "here " << endl;
                    }
                }
                else
                {
                    tokens.push_back({TokenType::Operator, string(1, c)});
                    i++;
                }
            }
            else if (isSeparator(c))
            {
                if (c == '#')
                {
                    string preprocessor;
                    i++;
                    while (i < input.length() && (isalnum(input[i]) || input[i] == '_'))
                    {
                        preprocessor.push_back(input[i]);
                        i++;
                    }
                    tokens.push_back({TokenType::Preprocessor, preprocessor});
                }
                else
                {
                    tokens.push_back({TokenType::Separator, string(1, c)});
                    i++;
                }
            }
            else if (c == '\"')
            {
                string str_literal;
                i++;
                while (i < input.length() && input[i] != '\"')
                {
                    if (input[i] == '\\' && i + 1 < input.length())
                    {
                        str_literal.push_back(input[i]);
                        i++;
                    }
                    str_literal.push_back(input[i]);
                    i++;
                }
                i++;
                tokens.push_back({TokenType::StringLiteral, str_literal});
            }
            else if (c == '\'')
            {
                string char_literal;
                i++;
                if (i < input.length())
                {
                    if (input[i] == '\\' && i + 1 < input.length())
                    {
                        char_literal.push_back(input[i]);
                        i++;
                    }
                    char_literal.push_back(input[i]);
                    i++;
                }
                i++;
                tokens.push_back({TokenType::CharLiteral, char_literal});
            }
            else
            {
                i++;
            }
        }
    }
    flushBuffer();
    return tokens;
}

int main()
{
    string input_filename;
    string output_filename;

    cout << "Enter the input file name: ";
    cin >> input_filename;
    cout << "Enter the output file name: ";
    cin >> output_filename;

    ifstream infile(input_filename);
    ofstream outfile(output_filename);

    if (!infile)
    {
        cerr << "Error opening the input file!" << endl;
        return 1;
    }

    if (!outfile)
    {
        cerr << "Error opening the output file!" << endl;
        return 1;
    }

    string input((istreambuf_iterator<char>(infile)), istreambuf_iterator<char>());

    auto tokens = lex(input);
    for (const auto &token : tokens)
    {
        // outfile << "Token type: " << static_cast<int>(token.type) << ", value: " << token.value << endl;
        outfile << "Token type: ";
        switch (token.type)
        {
        case TokenType::Keyword:
            outfile << "Keyword";
            break;
        case TokenType::Identifier:
            outfile << "Identifier";
            break;
        case TokenType::Integer:
            outfile << "Integer";
            break;
        case TokenType::Real:
            outfile << "Real";
            break;
        case TokenType::Operator:
            outfile << "Operator";
            break;
        case TokenType::Separator:
            outfile << "Separator";
            break;
        case TokenType::StringLiteral:
            outfile << "StringLiteral";
            break;
        case TokenType::CharLiteral:
            outfile << "CharLiteral";
            break;
        case TokenType::Comment:
            outfile << "Comment";
            break;
        case TokenType::Preprocessor:
            outfile << "Preprocessor";
            break;
        case TokenType::Unknown:
            outfile << "Unknown";
            break;
        }
        outfile << ", Value: " << token.value << endl;
    }

    cout << "Lexical analysis complete." << endl;

    return 0;
}

input.c文件 

用于词法分析器的输入文件

#include <stdio.h>
#define N 6

int main()
{
    // Single-Line Comments
    int a = 0;
    double b = 1.5;
    long c = 100L;
    char d = 'd';
    char s[6] = "hello";

    /*
        Multiline comment
        Multiline comment
    */
    if (a > 0)
    {
        printf("%s", s);
    }
    else
    {
        c = a + N;
    }
    return 0;
}

output.txt文件 

 词法分析器的输出结果

Token type: Preprocessor, Value: include
Token type: Operator, Value: <
Token type: Identifier, Value: stdio
Token type: Separator, Value: .
Token type: Identifier, Value: h
Token type: Operator, Value: >
Token type: Preprocessor, Value: define
Token type: Identifier, Value: N
Token type: Integer, Value: 6
Token type: Keyword, Value: int
Token type: Identifier, Value: main
Token type: Separator, Value: (
Token type: Separator, Value: )
Token type: Separator, Value: {
Token type: Comment, Value:  Single-Line Comments
Token type: Keyword, Value: int
Token type: Identifier, Value: a
Token type: Operator, Value: =
Token type: Integer, Value: 0
Token type: Separator, Value: ;
Token type: Keyword, Value: double
Token type: Identifier, Value: b
Token type: Operator, Value: =
Token type: Real, Value: 1.5
Token type: Separator, Value: ;
Token type: Keyword, Value: long
Token type: Identifier, Value: c
Token type: Operator, Value: =
Token type: Integer, Value: 100L
Token type: Separator, Value: ;
Token type: Keyword, Value: char
Token type: Identifier, Value: d
Token type: Operator, Value: =
Token type: CharLiteral, Value: d
Token type: Separator, Value: ;
Token type: Keyword, Value: char
Token type: Identifier, Value: s
Token type: Separator, Value: [
Token type: Integer, Value: 6
Token type: Separator, Value: ]
Token type: Operator, Value: =
Token type: StringLiteral, Value: hello
Token type: Separator, Value: ;
Token type: Comment, Value: 
        Multiline comment
        Multiline comment
    
Token type: Keyword, Value: if
Token type: Separator, Value: (
Token type: Identifier, Value: a
Token type: Operator, Value: >
Token type: Integer, Value: 0
Token type: Separator, Value: )
Token type: Separator, Value: {
Token type: Identifier, Value: printf
Token type: Separator, Value: (
Token type: StringLiteral, Value: %s
Token type: Separator, Value: ,
Token type: Identifier, Value: s
Token type: Separator, Value: )
Token type: Separator, Value: ;
Token type: Separator, Value: }
Token type: Keyword, Value: else
Token type: Separator, Value: {
Token type: Identifier, Value: c
Token type: Operator, Value: =
Token type: Identifier, Value: a
Token type: Operator, Value: +
Token type: Identifier, Value: N
Token type: Separator, Value: ;
Token type: Separator, Value: }
Token type: Keyword, Value: return
Token type: Integer, Value: 0
Token type: Separator, Value: ;
Token type: Separator, Value: }

注:在mylexer.cpp中,笔者定义了一个名为flushBuffer的Lambda函数,它将buffer中的内容添加到tokens向量,并清空buffer。

下面来详细解释一下这个Lambda函数:

  1. auto flushBuffer:我们使用auto关键字来定义一个名为flushBuffer的变量,它将存储我们的Lambda表达式。auto关键字告诉编译器根据Lambda表达式的类型自动推导flushBuffer的类型。

  2. [&]():这是Lambda表达式的开头部分,方括号[]内表示Lambda函数的捕获说明符。在这个例子中,我们使用&表示按引用捕获所有外部变量。这意味着在Lambda函数内部,我们可以访问并修改外部作用域中的变量,例如buffer和tokens。括号()表示Lambda函数没有参数。

  3. {}:这是Lambda函数的主体,大括号{}内包含了函数的实现。在这个例子中,我们检查buffer是否为空,如果不为空,我们将buffer中的内容添加到tokens向量,并清空buffer。

C++中的lambda表达式是一种创建匿名函数对象的便捷方式。自C++11起,lambda表达式成为了C++的一部分。它们通常用于定义简短的函数,可以直接在需要使用它们的地方定义。Lambda表达式的语法如下:

[capture](parameters) -> return_type { function_body }
  • capture:捕获列表,用于捕获来自定义lambda的作用域内的变量。捕获列表可以按值或按引用捕获变量。
  • parameters:函数参数列表,与常规函数参数列表类似。
  • return_type:返回类型(可选)。如果省略此部分,编译器会自动推导返回类型(通常为void或单个 return 语句的类型)。
  • function_body:函数体,包含实现所需功能的代码。

只看上面的概念还是太抽象了,我们举个简单的例子,来直观地感受一下Lambda表达式

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5};

    int factor = 3;

    // vector数组中每个元素都乘以factor
    for_each(numbers.begin(), numbers.end(), [factor](int& number) {
        number *= factor;
    });

    // 打印修改过的number数组
    for (const auto& number : numbers) {
        cout << number << " ";
    }

    return 0;
}

输出结果为:

3 6 9 12 15 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/480482.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【五一创作】力扣刷题实录(大厂用题)—— 1. 打家劫舍

1. 打家劫舍 某大厂 2022 年 9 月面试题挑战&#xff08;三&#xff09; 1.1 题目描述 力扣真题地址&#xff1a;https://leetcode.cn/problems/house-robber/?envTypestudy-plan-v2 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;…

Photoshop如何使用路径与矢量工具之实例演示?

文章目录 0.引言1.制作名片2.利用钢笔工具抠出复杂图像3.制作App图标4.制作软件登录界面5.将图片切成九宫格 0.引言 因科研等多场景需要进行绘图处理&#xff0c;笔者对PS进行了学习&#xff0c;本文通过《Photoshop2021入门教程》及其配套素材结合网上相关资料进行学习笔记总结…

简单搭建node后台(笔记用)

毕设过程 mongodb 配置 使用node写后台一些语法运用bug关于安装一款群控软件后&#xff0c;修改了环境变量导致后台崩溃![](https://img-blog.csdnimg.cn/7c684b2e318048b3ad1db78484e10e6a.jpeg) vue管理后台 mongodb 配置 https://blog.csdn.net/weixin_43405300/article/de…

Unity API详解——Vector3类

Vector3类是用于表示三维向量的类&#xff0c;其中的x、y和z成员表示向量在三个轴上的分量。Vector3类还包含许多常用的函数&#xff0c;例如计算向量长度、向量点积和向量叉积等等。此外&#xff0c;Vector3类还具有许多方便的操作&#xff0c;例如规范化向量、向量加法、向量…

数据预处理--sort乱序DICOM文件

我们直接从PACS系统里拷贝下来的图像&#xff0c;很多情况下是乱序的&#xff0c;随机命名的。如下图 从这个文件夹名字&#xff0c;我们只知道患者的 ID 信息&#xff0c;不知道这个图像是什么模态&#xff08;CT/MRI/Xray&#xff09;&#xff0c;也不知道扫的是哪个部位&…

【电子学会】2023年03月图形化一级 -- 甲壳虫走迷宫

甲壳虫走迷宫 1. 准备工作 &#xff08;1&#xff09;绘制如图所示迷宫背景图&#xff0c;入口在左下角&#xff0c;出口在右上角&#xff0c;线段的颜色为黑色&#xff1b; &#xff08;2&#xff09;删除默认小猫角色&#xff0c;添加角色&#xff1a;Beetle&#xff1b; …

Python探索性P图,四种增强方式快速玩转pillow库

嗨害大家好鸭&#xff01;我是爱摸鱼的芝士❤ 我们平时使用一些图像处理软件时&#xff0c; 经常会看到其对图像的亮度、对比度、色度或者锐度进行调整。 你是不是觉得这种技术的底层实现很高大上&#xff1f; 其实最基础的实现原理&#xff0c; 用 Python 实现只需要几行…

【力扣周赛】第343场周赛

【力扣周赛】第343场周赛 2660&#xff1a;保龄球游戏的获胜者题目描述解题思路 2661&#xff1a;找出叠涂元素题目描述解题思路 2660&#xff1a;保龄球游戏的获胜者 题目描述 描述&#xff1a;给你两个下标从 0 开始的整数数组 player1 和 player2 &#xff0c;分别表示玩家…

系统集成项目管理工程师 笔记(第10章 项目质量管理)

文章目录 10.1.2 质量管理及其 发展史 35610.1.3 项目质量管理 35810.2.2 规划质量管理的输入 35910.2.3 规划质量管理的工具与技术 3601、成本效益分析法2、质量成本法&#xff08;一致性成本【预防、评价】 和 非一致性成本【内部、外部】&#xff09;3、七种基本质量工具&am…

【AI作诗】主流平台介绍+自主搭建

诗歌总是属于文人的浪漫&#xff0c;但随着技术的发展&#xff0c;理科生文艺起来&#xff0c;也就没文科生什么事了&#xff08;开玩笑的&#xff09;。通过本篇文章&#xff0c;笔者将给大家介绍主流的AI诗歌创作平台及如何自己搭建&#xff0c;以供大家学习参考。 技术的进…

0、Java开发常见(并发,JVM)

并发 问题详解请谈谈你对volatile的理解linkCAS你知道吗&#xff1f;link原子类Atomiclnteger的ABA问题谈谈?原子更新引用知道吗&#xff1f;link我们知道ArrayList是线程不安全&#xff0c;请编码写一个不安全的案例并给出解决方案link公平锁/非公平锁/可重入锁/递归锁/自旋…

快解析赋能企业私有云部署

很多企业形成了以总部为中心的多点生产体系结构&#xff0c;并借助网络化办公工具搭建跨区域协同办公系统&#xff0c;满足总部与分支机构间的信息互通&#xff0c;进而促进异地业务的信息共享&#xff0c;提高办公处理效率和综合管理水平。 北京某信息技术公司&#xff0c;主…

C# 使用OpenCV基本图像操作功能

C# 使用OpenCV OpenCV是一个开源的跨平台计算机视觉和机器学习软件库&#xff0c;可以运行在Linux、Windows、Android和Mac OS操作系统上。C#在上位机开发中比较常用&#xff0c;有些项目需要在上位机上加入一些机器视觉相关的功能&#xff0c;在下面简单介绍了C#中使用OpenCV…

JVM-0426

对象内存布局 对象的实例化 创建对象的方式&#xff1a; new 最常见的方式变形1&#xff1a;XX的静态方法 Class &#xff1a; 调用froName( )方法变形2&#xff1a;xxxBuilder / xxxFactory的静态方法 Class的newInstance( )&#xff1a;反射的方式&#xff0c;只能调用空参的…

自动控制原理笔记-频率响应法-频率特性的概念

目录 频率响应法&#xff1a; 频率特性的概念&#xff1a; 一、频率特性的定义&#xff1a; 二、频率特性的求法: 三、频率特性的物理意义: 四、频率特性的图形表示方法: 频率响应法&#xff1a; 基本思想&#xff1a;通过开环频率特性的图形对系统进行分析。 主要优点&…

【2023华中杯数学建模】B 题 小学数学应用题相似性度量及难度评估详细建模方案及实现代码

更新时间&#xff1a;2023-5-1 14:00 1 题目 B 题 小学数学应用题相似性度量及难度评估 某 MOOC 在线教育平台希望能够进行个性化教学&#xff0c;实现用户自主学习。在用户学习时&#xff0c;系统从题库中随机抽取若干道与例题同步的随堂测试题&#xff0c;记录、分析学生的学…

java的类加载浅析

类加载 类加载器 类加载器是Java虚拟机&#xff08;JVM&#xff09;的一个组成部分&#xff0c;它的主要任务是在运行时动态加载类和资源&#xff0c;以便程序能够使用它们。类加载器从文件系统、网络或其他来源中获取类的字节码&#xff0c;并将其转换为JVM可执行的形式&…

机器学习基础知识之交叉验证

文章目录 交叉验证定义1、随机子抽样验证2、K折交叉验证3、留一法交叉验证4、自助采样验证 交叉验证定义 在使用某一个数据集对模型进行训练时&#xff0c;模型的实际训练情况会受到数据集的直接影响&#xff0c;且其实际训练结果是难以确定的&#xff0c;极有可能出现欠拟合与…

【实验报告】实验四、彩色图像处理

一、实验目的 使用MatLab软件对图像进行彩色处理&#xff0c;熟悉使用MatLab软件进行图像彩 色处理的有关方法&#xff0c;并体会到图像彩色处理技术以及对图像处理的效果。 二、实验原理 &#xff08;一&#xff09;一幅RGB图像就是彩色像素的一个M x N x 3数组&#xff0…

视频搬砖项目【一个技术员是如何轻松利用视频搬运项目做到日入2000+】

无门槛人人可做副业项目&#xff0c;视频搬砖收益&#xff0c;实测一天2000&#xff01; 今天给大家分享一个微信看一看 的项目&#xff0c;操作非常简单&#xff0c;小白也很容易上手&#xff0c;不需要像某音一样去卖货&#xff0c;只要发布作品就能够有收益。 第一个、项目…