编译原理词法分析器

news2024/11/25 14:49:49

算法描述

对于给出的源代码,我们按行将其读入,对于每一行单独进行词法分析。

  1. 过滤行前后空格
  2. 对字符串进行词语的分割
    • 有空格则把空格前的字符归为一个词
    • 比较上一个字符和当前字符是否需要进行分割
  3. 检查词语是否合法
  4. 词语合法则按 [待测代码中的单词符号] [TAB] <[单词符号种别],[单词符号内容]> 进行输出,其中,单词符号种别为 KW(关键字)、OP(运算符)、SE(界符)、IDN(标识符)INT(整形数);单词符号内容 KW、OP、SE 为其编号(见单词表),其余为其值。
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>

using namespace std;

const int WORD_NUM = 26;
const string WORD[WORD_NUM] = {
    "int", "void", "return", "const", "main", "struct", "+",  "-",  "*",  "/",
    "%",   "=",    ">",      "<",     "==",   "<=", ">=", "!=", "&&",
    "||",  "(",    ")",      "{",     "}",    ";",  ",",
};
const string OPERATOR = "+-*/%><=&|";
const string SEPARATER = "(){};,[]";
int kws = 0, kwe = 6, ops = 6, ope = 20, ses = 20, see = 26;

class Analyzer {
  private:
    vector<string> lines;
    vector<string> token;
    string fileName;
    ofstream fout;

    int isWord(string word) {
        for(int i = 0; i < WORD_NUM; i++) {
            if(word == WORD[i])
                return i;
        }
        return -1;
    }
    bool isKeyWord(int idx) {
        return kws <= idx && idx < kwe;
    }
    bool isOperator(int idx) {
        return ops <= idx && idx < ope;
    }
    bool isOperator(char ch) {
        return OPERATOR.find(ch) != OPERATOR.npos;
    }
    bool isSeparater(int idx) {
        return ses <= idx && idx < see;
    }
    bool isSeparater(char ch) {
        return SEPARATER.find(ch) != SEPARATER.npos;
    }
    inline bool isNumber(char ch) {
        return ch >= '0' && ch <='9';
    }
    bool isInt(string word) {
        for(int i = 0; i < word.size(); i++) {
            if(!isNumber(word[i]))
                return false;
        }
        return true;
    }
    inline bool isCharacter(char ch) {
        return ch >= 'a' && ch <= 'z' || ch >='A' && ch <= 'Z';
    }
    bool isPartOfIdentifier(char c) {
        return isCharacter(c) || isNumber(c) || c == '_';
    }
    bool isIdentifier(string word) {
        if(isNumber(word[0])) {
            return false;
        }
        for(int i = 1; i < word.size(); i++) {
            if(!isPartOfIdentifier(word[i]))
                return false;
        }
        return true;
    }
    //输出
    inline void record(string word, string type, string content) {
        char TAB = '\t';
        string msg = word + TAB + "<" + type + "," + content + ">";
        fout << msg << endl;
        token.push_back(msg);
    }
    //int 转 string
    string to_string(int val) {
        stringstream ss;
        ss << val;
        string result;
        ss >> result;
        return result;
    }
    //分析一个单词
    bool anaylyseWord(string word) {
        if(word.empty()) {
            return true;
        }
        int idx = isWord(word);
        if(idx > -1) {
            string type;
            if(isKeyWord(idx)) type = "KW";
            if(isOperator(idx)) type = "OP";
            if (isSeparater(idx)) type = "SE";
            record(word, type, to_string(idx + 1));
            return true;
        } else {
            if(isIdentifier(word)) {
                record(word,"IND", word);
                return true;
            }
            if(isInt(word)) {
                record(word,"INT", word);
                return true;
            }
        }
        fout << "ERROR detected!" << endl;
        cout << "ERROR detected!" << endl;
        return false;
    }
    //去除字符串前后空格
    string trim(string s) { 
        if(s == "") {
            return "";
        }
        int l = 0, r = s.size() - 1;
        while(s[l] == ' ' && l < s.size()) l++;
        while(s[r] == ' ' && r > l) r--;
        return s.substr(l,r + 1);
    }

    //判断两个相邻字符是否需要分割
    bool check(char a, char b) {
        if ((isOperator(a) && !isOperator(b)) ||
            (!isOperator(a) && isOperator(b)) || isSeparater(a) ||
            (!isSeparater(a) && isSeparater(b)))
            return false;
        return true;

    }

  public:
    Analyzer(string fileName) {
        readFile(fileName);
    }
    ~Analyzer() {
        fout.close();
    }
    vector<string> getToken() {
        return token;
    }

    void readFile(string fileName) {
        this->fileName = fileName;
        fstream fin(fileName.c_str());
        if (!fin.is_open()) {
            throw "无法打开文件";
        }
        string line;
        while (getline(fin, line)) {
            line = trim(line);
            if(!line.empty())
                lines.push_back(line);
        }
        fin.close();
        // fout.open("token.txt");
        fout.open(fileName.substr(0,fileName.find_last_of(".")) + ".out");
    }

    void analyse() {
        int l = 0;
        string word = "";
        while(l < lines.size()) {
            string line = lines[l++]; //读入一行
            word.clear();
            for(int i = 0; i < line.size(); i++) {
                if(line[i] == ' ' || line[i] == '\t') { //分割单词
                    if(!anaylyseWord(word)) return; //判断单词是否合法并打印
                    word.clear();
                    continue;
                }
                if(!check(word[word.size() - 1], line[i])) { //分割单词
                    if(!anaylyseWord(word)) return; //判断单词是否合法并打印
                    word.clear();
                }
                word += line[i]; 
            }
            anaylyseWord(word); //到行末结束后,将剩余的拼成一个单词
        }
    }
};

int main() {
    try {
        Analyzer analyzer("a.sy");
        analyzer.analyse();
        system("pause");
    } catch (const char *msg) {
        cout << msg << endl;
    }
    return 0;
}

算法NFA和DFA及单词表

请添加图片描述
请添加图片描述

单词符号种类种别码
int关键字1
void关键字2
return关键字3
const关键字4
main关键字5
struct关键字6
+运算符7
-运算符8
*运算符9
/运算符10
%运算符11
=运算符12
<运算符13
>运算符14
==运算符15
<=运算符16
>=运算符17
!=运算符18
&&运算符19
||运算符20
(界符21
)界符22
{界符23
}界符24
;界符25
,界符26

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

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

相关文章

idea spring initializr创建项目报错

闲来无事就想搞个项目练练手&#xff0c;没想到直接给我卡在项目创建上了&#xff0c;一个个问题最终迎刃而解。 1.上来就给我报了个maven的错 未解析的插件: ‘org.apache.maven.plugins:maven-resources-plugin:3.3.1’ 不慌&#xff0c;应该是maven的路径有问题&#xff0c…

Ardupilot开源飞控之VTOL之旅:配件规格

Ardupilot开源飞控之VTOL之旅&#xff1a;配件规格 1. 源由2. 飞控板 Aocoda-RC H743Dual3. PDB分电板 Aocoda-RC PDB30604. GPS BN8805. 摄像头 RunCam 1200TVL6. 模拟图传 JHEMCU RuiBet Tran-3016W 5.8GHZ 1.6W7. 打印件7.1 飞控/GPS座子7.2 VTX/天线座子7.3 接收机天线座 8…

视频批量剪辑秘籍:批量AI智剪技巧,提升剪辑效率

在视频制作过程中&#xff0c;剪辑是一项重要的工作。然而&#xff0c;对于许多创作者来说&#xff0c;逐个剪辑视频会耗费大量的时间和精力。为了提高效率&#xff0c;批量剪辑成为了必要的手段。在进行批量剪辑之前&#xff0c;首先要明确自己的需求和素材。了解要剪辑的视频…

理解国外大佬用Web做出来跨窗口渲染动画效果

今天刷抖音看见国外一个大佬用Web做出来一个可以跨多浏览器窗口实时互动的渲染动画效果,觉得非常新奇,我就去看了一下源码,作者还写了一个非常好的例子帮助理解,我自己也仿写了作者的例子加深理解 **GitHub预览地址**麻烦帮忙点亮星星谢谢哈哈哈~ 整体思路是监听visibilityStat…

Windows系统下更新后自带的画图软件出现马赛克bug

一.bug的样子 在使用橡皮后&#xff0c;原来写的内容会变成马赛克。而我们希望它是纯白色的。 二.解决方法 第一步 第二步 第三步 三. 解决后的效果 用橡皮擦随便擦都不会出现马赛克了。 更新过后&#xff0c;想用win自带的画图软件会出现bug,希望微软大佬能够尽早解决bug。

QT基础开发笔记

用VS 写QT &#xff0c;设置exe图标的方法&#xff1a; 选定工程--》右键--》添加---》资源--》 QString 字符串用法总结说明 Qt QString 增、删、改、查、格式化等常用方法总结_qstring 格式化-CSDN博客 总结来说&#xff1a; QString 的 remove有两种用法&#xff0c;&am…

Zephyr:Direct Distillation of LM Alignment

Zephyr&#xff1a;Direct Distillation ofLM Alignment IntroductionMethod Introduction dSFT已经被可以提升模型的指令遵循能力的准确性&#xff0c;但是student model 不会超过 teacher model。 作者认为 dSFT虽然可以让模型更好的理解用户意图&#xff0c;但是无法与人类…

【笔记】小白学习电路维修

学习视频&#xff08;b站&#xff09;&#xff1a;从0开始学电路 从0开始学电路维修 p1 黄色长方体元件P2 故障率最高的元件p3带芯铜丝线圈是什么区分电感和变压器接入电路分析&#xff1a; p1 黄色长方体元件 安规电容&#xff1a;分为x y两种 位置&#xff1a;通常位于交…

[C++]指针与结构体

标题 一.指针1.指针的定义和使用2.指针所占的内存空间3.空指针与野指针4.const修饰指针5.指针和数组6.指针和函数 二.结构体1.结构体的定义与使用2.结构体数组3.结构体指针4.结构体的嵌套使用5.结构体做函数参数6.结构体中const使用场景7.案例练习 一.指针 作用: 可以通过指针…

Liunx系统使用超详细(一)

目录 一、Liunx系统的认识 二、Liunx和Windows区别 三、Liunx命令提示符介绍 四、Liunx目录结构 一、Liunx系统的认识 Linux系统是一种开源的、类Unix操作系统内核的实现&#xff0c;它基于Unix的设计原理和思想&#xff0c;并在全球范围内广泛应用。以下是对Linux系统的详…

Drools 7 JMX Mbean 及Metric 分析

Mbean mbean的打开很简单&#xff0c;使用jmx启动参数&#xff1a; -Dcom.sun.management.jmxremote.port9999 -Ddrools.mbeansenabled -Dcom.sun.management.jmxremote.authenticatefalse -Dcom.sun.management.jmxremote.sslfalse 但通过jconsole能直观看到的东西也很…

文本编辑 UTF-8 BOM 中的BOM释义

参考资料 UTF8のBOM無しとBOM付きの違いBOMなしUTF-8によってWindowsでもたらされる困惑文字コードをUTF-8 BOMなし(UTF-8N)でファイル保存をする方法 目录 一. 前提二. BOM三. CSV文件中的表现 一. 前提 在使用Windows自带的记事本编辑.csv文件的时候&#xff0c;准备保存为…

openpnp - 自动换刀设置 - 使用克隆功能降低风险

文章目录 openpnp - 自动换刀设置 - 使用克隆功能降低风险概述笔记需要注意的地方将一个做好的吸嘴作为这排其他吸嘴的模板END openpnp - 自动换刀设置 - 使用克隆功能降低风险 概述 自动换刀设置时, 很危险, 动不动就撞刀. 如履薄冰啊:( 看到openpnp在自动换刀时, 有个克隆功…

每日一练:“打家劫舍”(House Robber)问题 III

有想要了解打家劫舍初级问题的&#xff0c;可以点击下面链接查看&#xff01; 每日一练&#xff1a;“打家劫舍“&#xff08;House Robber&#xff09;问题 I   每日一练&#xff1a;“打家劫舍“&#xff08;House Robber&#xff09;问题 II 1. 问题 房屋形成一棵二叉树&…

时间序列预测 — LSTM实现单变量风电滚动预测(Keras)

目录 1 数据处理 1.1 数据集简介 1.2 数据集处理 2 模型训练与预测 2.1 模型训练 2.2 模型滚动预测 2.3 结果可视化 1 数据处理 1.1 数据集简介 实验数据集采用数据集5&#xff1a;风电机组运行数据集&#xff08;下载链接&#xff09;&#xff0c;包括风速、风向、温…

每日一题:LeetCode-LCR 143.子结构判断

每日一题系列&#xff08;day 05&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

Android之高级UI

系统ViewGroup原理解析 常见的布局容器: FrameLayout, LinearLayout,RelativeLayoout,GridLayout 后起之秀&#xff1a;ConstraintLayout,CoordinateLayout Linearlayout Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {if (mOrientation …

探索计算机视觉:深度学习与图像识别的融合

探索计算机视觉&#xff1a;深度学习与图像识别的融合 摘 要&#xff1a; 本文将探讨计算机视觉领域中的深度学习技术&#xff0c;并重点关注图像识别方面的应用。我们将介绍卷积神经网络&#xff08;CNN&#xff09;的原理、常用的图像数据集以及图像识别的实际应用场景&…

OpenWrt Lan口上网设置

LAN口上网设置 连接上openwrt&#xff0c;我用的 倍控N5105&#xff0c;eth0&#xff0c;看到Openwrt的IP是10.0.0.1 在 网络 -> 网口配置 -> 设置好 WAN 口和 LAN 口 初次使用经常重置 openwrt 所以我设置的是 静态IP模式 - 网络 -> 防火墙 -> 常规设置 ->…

机器学习【04重要】pycharm中关闭jupyter服务器

直接关掉pycharm 不行 点红方块关闭 不行 我们曲线进行 我们的方法成功截图 实现全程不在服务器上操作 首先点击下图 点击退出&#xff0c;即可 查看端口