利用正则匹配原理 为C++语法 做词法分析与着色


来张着色效果图先:
它已经按照规则识别出了:
字符串,标识符,数字.

因为没有写 多行字符串,续行符,#预处理命令等规则,所以它看起来略微混乱.文字乱码是因为输出环境是ANSI…

简易原理:

  • 定义不同规则的正则表达式
  • 对待处理的文本进行正则匹配,捕获匹配的部分.至到待匹配文本结束.
    • 如果没有匹配就是词法错误
    • 如果有匹配就将捕获到的片段填入Token中
  • 针对前文生成的Token流进行类型遍历和输出
    • 将Token文本以不同的颜色输出
      没了。。。
      在这里插入图片描述

原理

两周自制脚本语言:
Lex(词法分析)使用正则来做.

  1. 用一个正则匹配所有可能的情况:
  • 空格换行
  • 注释
  • 数字
  • 字符串
  • 标志符
  1. 通过命中的匹配.将其类型和值保存.
  2. 对该集合进行遍历.渲染相应的颜色.

习得

这次算是我第一次正规完成Lex.效果很喜人.
编译器,就是这样:数据->token流->tree->遍历树做想做的事情->生成目标
这次打通了token流,能实现 颜色渲染.

展望

我曾经遇到的困难是:

  • 多种可能的分析
    这涉及到优先级问题和向前看问题.

不足

正则还是太复杂了.一大堆…
可以设计成多个表达式的拼接.
目前没有实现 多个标志符的匹配,以及对称内容的匹配:<> /**/

代码如下:

#include <iostream>
#include <string>
#include <regex>
#include <vector>


class TOKEN
{
public:
    std::string valueGet() {
        return value;
    }
    void valueSet(std::string str) {
        value = str;
    }
    std::string typeGet() {
        return type;
    }
    void typeSet(std::string str) {
        type = str;
    }

private:
    std::string value;
    std::string type;


};
#include <windows.h>
void SetColor(unsigned short forecolor = 4, unsigned short backgroudcolor = 0)
{
    HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); //获取缓冲区句柄
    SetConsoleTextAttribute(hCon, forecolor | backgroudcolor); //设置文本及背景色
}

std::vector<TOKEN*> Lex(std::string s) {
    std::vector<TOKEN*> m_token;
    std::smatch m;
    //|\\p{Punct}   !|\"|#|\\$|%|&|'|\\(|\\)|\\*|\\+|,|-|\\.|/|:|;|<|=|>|\\?|@|\\[|\\\|\\]|\\^|_|`|\\{|\\||\\}|~
    std::regex e("(\\s+)|((//.*)|([0-9]+)|(\"(\\\\\"|\\\\|\\\\n|[^\"])*\")|([A-Z_a-z][A-Z_a-z0-9]*|==|<=|>=|&&|\\/|\\*|\\-|\\+|\\(|\\)|>|<|=|%|&|;|\\{|\\}|!|\"|#|\\$|%|&|'|\\(|\\)|\\*|\\+|,|-|\\.|/|:|;|<|=|>|\\?|@|\\[|\\|\\]|\\^|_|`|\\{|\\||\\}|~))?");   // matches words beginning by "sub"
    while (std::regex_search(s, m, e)) {
        if (m[1].length())
        {
            TOKEN* p = new TOKEN();
            p->valueSet(m[1].str());
            p->typeSet("空格换行");
            m_token.push_back(p);
        }
        else if (m[3].length()) {
            TOKEN* p = new TOKEN();
            p->valueSet(m[3].str());
            p->typeSet("注释");
            m_token.push_back(p);
        }
        else if (m[4].length()) {
            TOKEN* p = new TOKEN();
            p->valueSet(m[4].str());
            p->typeSet("数字");
            m_token.push_back(p);
        }
        else if (m[5].length()) {
            TOKEN* p = new TOKEN();
            p->valueSet(m[5].str());
            p->typeSet("字符串");
            m_token.push_back(p);
        }
        else if (m[7].length()) {
            TOKEN* p = new TOKEN();
            p->valueSet(m[7].str());
            p->typeSet("标识符");
            m_token.push_back(p);
        }
        s = m.suffix().str();
        if (s.empty())break;
        if (0 == m[0].length()) {
            std::cout << "发生无法识别的类型.从下一行开始识别" << std::endl;
            auto  i=s.find('\n');
        
            if (i != std::string::npos) {
                s = s.substr(i);
                if (s.length() > 1) {
                    s=s.substr(1);
                }
                else {
                    break;
                }
            }
            else {
                break;
            }
        }
    }
    return m_token;
}

#include <string>
#include <fstream>
#include <sstream>


#define 黑背景 0
#define 亮白背景 BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY

#define 白色前景 FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
#define 亮蓝前景 FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define 蓝色前景 FOREGROUND_BLUE
#define 棕色前景 FOREGROUND_RED | FOREGROUND_GREEN
#define 绿色前景 FOREGROUND_GREEN

int main()
{
    std::string s = "function abc() {\r\n"\
        "        if (a | b)//zhu shi\r\n"\
        "            printf(\"ok\");\r\n"\
        "    }\r\n"\
        "        \r\n";



    std::ifstream t("file2.cpp");
    std::stringstream buffer;
    buffer << t.rdbuf();
    std::string contents(buffer.str());

    auto m_token = Lex(contents);
    /*
    剩下的工作是: 把不同位置的字符串读出来,再按想法做处理

    */



    std::string key_words_text = "if else for while { } ( ) ; == != ! | bool int float double auto ? : > = < * + - * / \\ . break continue return new delete try const static";
    std::istringstream iss(key_words_text);
    std::vector<std::string> key_words(std::istream_iterator<std::string>{iss},
        std::istream_iterator<std::string>());

    for (auto t : m_token) {
        if (t->typeGet() == "空格换行") {
            SetColor(白色前景, 亮白背景);
        }
        else if (t->typeGet() == "注释") {
            SetColor(绿色前景, 亮白背景);
        }
        else if (t->typeGet() == "数字") {
            SetColor(FOREGROUND_RED|FOREGROUND_INTENSITY, 亮白背景);
        }
        else if (t->typeGet() == "字符串") {
            SetColor(棕色前景, 亮白背景);
        }
        else if (t->typeGet() == "标识符") {
            /*
            如果是关键字里的东西 则 显示 亮蓝
            */
            bool b = false;
            for (auto tmp : key_words) {
                if (tmp == t->valueGet()) {
                    b = true;
                    SetColor(亮蓝前景, 亮白背景);
                }
            }
            if (!b) {
                SetColor(绿色前景, 亮白背景);
            }



        }
        std::cout << t->valueGet();
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值